mirror of
https://github.com/temporalio/skill-temporal-developer.git
synced 2026-09-14 13:52:58 +08:00
b5719bc143
* Add initial skill for testing, which is simply Steve's skill (#1) * Add initial skill for testing, which is simply Steve's skill * Rename skill to 'temporal-dev' and update version Updated skill name and version for Temporal Python. * Use claude to merge Steve's, Max's, and Mason's skills. (#2) * Use claude to merge Steve's, Max's, and Mason's skills. Did a review pass using claude's skill devlopment skills * Add missing things from Steve * trigger tweaks * Add in common gotchas from Johann * add simple feedback mechanism (#3) * Change skill name to kebab-case, for compatibility with Amp and Cline (#7) * Clean up references/core/ai-integration.md * Clean up references/core/common-gotchas.md * Clean up references/core/common-gotchas.md * Clean up references/core/determinism.md * Clean up references/core/determinism.md * Update error-reference.md * Update interactive-workflows.md * Clean up patterns.md * Cut shell scripts * Edit troubleshooting.md * remove interceptors for now * remove dynamic workflows * clarify on heartbeating of async activity completions, and prompt it a bit in relation to signals * Improve references/python/advanced-features.md * Use explicit namespace in connect * remove duplicated content from determinism.md, clean up * Improve references/python/data-handling.md * Prefer start_to_close_timeout * don't explicitely provide defaults for retry policies * error-handling.md cleanup * move idempotency patterns to patterns.md * remove multi-param activities * small edits * Unify sandbox stuff into one file * local activities aren't experimental * Clean up references/python/sync-vs-async.md * Cleanup observability.md, remove duplicated search attributes * Cut otel for now * cut a lot of duplicate stuff from python gotchas, address comments * de-duplicate content * Lots of improvements to testing * cleanup to top level of skill (like CLI install instructions), and to top-level of python * Improve patterns.md * clean up ai-patterns.md * Update readme with installation instructions * remove ts directory * De-couple core from python and TypeScript as much as possible * Remove TypeScript hints * add prompting for feedback at startup - wait for ethan on slack channel * shorten url * Update slack channel * Automated pass over on python cleanup & deduplication * Remove multi-patching from Python, since its obvious, dont waste tokens on it. (#34) * Add TypeScript (#31) Adds initial support for TypeScript to the skill --------- Co-authored-by: James Watkins-Harvey <mjameswh@users.noreply.github.com> Co-authored-by: Chris Olszewski <chrisdolszewski@gmail.com> * Fix typos and reference links (#36) * Fix typos and reference links * 2 more typo fixes * quick edit to readme (#37) * Fix saga compensations to run under cancellation protection (#43) When a workflow is cancelled mid-saga, compensations must run in a cancellation-protected scope, otherwise they are immediately cancelled before they can execute. - Python: wrap compensation loop in asyncio.shield() so it runs even when the workflow receives a CancelledError - TypeScript: wrap compensation loop in CancellationScope.nonCancellable() so it runs even when the root scope is cancelled (per official docs: "Cleanup logic must be in a nonCancellable scope") - TypeScript: also fix compensation registration order — register BEFORE calling the activity (was already correct in Python) Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com> * Update readme for public preview (#45) * a few more readme tweaks (#46) * Add MIT License to the project (#47) * Add Go (supersedes other PR) (#38) * progress on go * Go translation workflow completed. * missed a few spots * Manual edits * Address feedback * Add gotcha about anonymous local activities * Sample code for payload converter * clarify sdk protection mechanisms * Setup CODEOWNERS to AI SDK team (#48) * Align version number in SKILL.md and plugin.json. (#49) --------- Co-authored-by: James Watkins-Harvey <mjameswh@users.noreply.github.com> Co-authored-by: Chris Olszewski <chrisdolszewski@gmail.com> Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
243 lines
7.3 KiB
Markdown
243 lines
7.3 KiB
Markdown
# Temporal Go SDK Reference
|
|
|
|
## Overview
|
|
|
|
The Temporal Go SDK (`go.temporal.io/sdk`) provides a strongly-typed, idiomatic Go approach to building durable workflows. Workflows are regular exported Go functions. The Go SDK does not have an automatic sandbox -- determinism is the developer's responsibility, aided by the `workflowcheck` static analysis tool.
|
|
|
|
## Quick Start
|
|
|
|
**Add Dependency:** In your Go module, add the Temporal SDK:
|
|
```bash
|
|
go get go.temporal.io/sdk
|
|
```
|
|
|
|
**workflows/greeting.go** - Workflow definition:
|
|
```go
|
|
package workflows
|
|
|
|
import (
|
|
"time"
|
|
|
|
"go.temporal.io/sdk/workflow"
|
|
)
|
|
|
|
func GreetingWorkflow(ctx workflow.Context, name string) (string, error) {
|
|
ao := workflow.ActivityOptions{
|
|
StartToCloseTimeout: time.Minute,
|
|
}
|
|
ctx = workflow.WithActivityOptions(ctx, ao)
|
|
|
|
var result string
|
|
err := workflow.ExecuteActivity(ctx, "Greet", name).Get(ctx, &result)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return result, nil
|
|
}
|
|
```
|
|
|
|
**activities/greet.go** - Activity definition:
|
|
```go
|
|
package activities
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
)
|
|
|
|
type Activities struct{}
|
|
|
|
func (a *Activities) Greet(ctx context.Context, name string) (string, error) {
|
|
return fmt.Sprintf("Hello, %s!", name), nil
|
|
}
|
|
```
|
|
|
|
**worker/main.go** - Worker setup:
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"log"
|
|
|
|
"yourmodule/activities"
|
|
"yourmodule/workflows"
|
|
|
|
"go.temporal.io/sdk/client"
|
|
"go.temporal.io/sdk/worker"
|
|
)
|
|
|
|
func main() {
|
|
c, err := client.Dial(client.Options{})
|
|
if err != nil {
|
|
log.Fatalln("Unable to create client", err)
|
|
}
|
|
defer c.Close()
|
|
|
|
w := worker.New(c, "my-task-queue", worker.Options{})
|
|
|
|
w.RegisterWorkflow(workflows.GreetingWorkflow)
|
|
w.RegisterActivity(&activities.Activities{})
|
|
|
|
err = w.Run(worker.InterruptCh())
|
|
if err != nil {
|
|
log.Fatalln("Unable to start worker", err)
|
|
}
|
|
}
|
|
```
|
|
|
|
**Start the dev server:** Start `temporal server start-dev` in the background.
|
|
|
|
**Start the worker:** Run `go run worker/main.go` in the background.
|
|
|
|
**starter/main.go** - Start a workflow execution:
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
|
|
"yourmodule/workflows"
|
|
|
|
"github.com/google/uuid"
|
|
"go.temporal.io/sdk/client"
|
|
)
|
|
|
|
func main() {
|
|
c, err := client.Dial(client.Options{})
|
|
if err != nil {
|
|
log.Fatalln("Unable to create client", err)
|
|
}
|
|
defer c.Close()
|
|
|
|
options := client.StartWorkflowOptions{
|
|
ID: uuid.NewString(),
|
|
TaskQueue: "my-task-queue",
|
|
}
|
|
|
|
we, err := c.ExecuteWorkflow(context.Background(), options, workflows.GreetingWorkflow, "my name")
|
|
if err != nil {
|
|
log.Fatalln("Unable to execute workflow", err)
|
|
}
|
|
|
|
var result string
|
|
err = we.Get(context.Background(), &result)
|
|
if err != nil {
|
|
log.Fatalln("Unable to get workflow result", err)
|
|
}
|
|
|
|
fmt.Println("Result:", result)
|
|
}
|
|
```
|
|
|
|
**Run the workflow:** Run `go run starter/main.go`. Should output: `Result: Hello, my name!`.
|
|
|
|
## Key Concepts
|
|
|
|
### Workflow Definition
|
|
- Exported function with `workflow.Context` as the first parameter
|
|
- Returns `(ResultType, error)` or just `error`
|
|
- Signature: `func MyWorkflow(ctx workflow.Context, input MyInput) (MyOutput, error)`
|
|
- Use `workflow.SetQueryHandler()`, `workflow.SetUpdateHandler()` for handlers
|
|
- Register with `w.RegisterWorkflow(MyWorkflow)`
|
|
|
|
### Activity Definition
|
|
- Regular function or struct methods with `context.Context` as the first parameter
|
|
- Struct methods are preferred for dependency injection
|
|
- Signature: `func (a *Activities) MyActivity(ctx context.Context, input string) (string, error)`
|
|
- Register struct with `w.RegisterActivity(&Activities{})` (registers all exported methods)
|
|
|
|
### Worker Setup
|
|
- Create client with `client.Dial(client.Options{})`
|
|
- Create worker with `worker.New(c, "task-queue", worker.Options{})`
|
|
- Register workflows and activities
|
|
- Run with `w.Run(worker.InterruptCh())`
|
|
|
|
### Determinism
|
|
|
|
**Workflow code must be deterministic!** The Go SDK has no sandbox -- determinism is enforced by convention and tooling.
|
|
|
|
Use Temporal replacements instead of native Go constructs:
|
|
- `workflow.Go()` instead of `go` (goroutines)
|
|
- `workflow.Channel` instead of `chan`
|
|
- `workflow.Selector` instead of `select`
|
|
- `workflow.Sleep()` instead of `time.Sleep()`
|
|
- `workflow.Now()` instead of `time.Now()`
|
|
- `workflow.GetLogger()` instead of `log` / `fmt.Println` for replay-safe logging
|
|
|
|
Use the **`workflowcheck`** static analysis tool to catch non-deterministic code:
|
|
```bash
|
|
go install go.temporal.io/sdk/contrib/tools/workflowcheck@latest
|
|
workflowcheck ./...
|
|
```
|
|
|
|
Read `references/core/determinism.md` and `references/go/determinism.md` to understand more.
|
|
|
|
## File Organization Best Practice
|
|
|
|
**Use separate packages for workflows, activities, and worker.** Activities as struct methods enable dependency injection at the worker level.
|
|
|
|
```
|
|
myapp/
|
|
├── workflows/
|
|
│ └── greeting.go # Only Workflow functions
|
|
├── activities/
|
|
│ └── greet.go # Activity struct and methods
|
|
├── worker/
|
|
│ └── main.go # Worker setup, imports both
|
|
└── starter/
|
|
└── main.go # Client code to start workflows
|
|
```
|
|
|
|
**Activities as struct methods for dependency injection:**
|
|
```go
|
|
// activities/greet.go
|
|
type Activities struct {
|
|
HTTPClient *http.Client
|
|
DB *sql.DB
|
|
}
|
|
|
|
func (a *Activities) FetchData(ctx context.Context, url string) (string, error) {
|
|
// Use a.HTTPClient, a.DB, etc.
|
|
}
|
|
```
|
|
|
|
```go
|
|
// worker/main.go - inject dependencies at worker startup
|
|
activities := &activities.Activities{
|
|
HTTPClient: http.DefaultClient,
|
|
DB: db,
|
|
}
|
|
w.RegisterActivity(activities)
|
|
```
|
|
|
|
## Common Pitfalls
|
|
|
|
1. **Using native goroutines/channels/select** - Use `workflow.Go()`, `workflow.Channel`, `workflow.Selector`
|
|
2. **Using `time.Sleep` or `time.Now`** - Use `workflow.Sleep()` and `workflow.Now()`
|
|
3. **Iterating over maps with `range`** - Map iteration order is non-deterministic; sort keys first
|
|
4. **Forgetting to register workflows/activities** - Worker will fail tasks for unregistered types
|
|
5. **Registering activity functions instead of struct** - Use `w.RegisterActivity(&Activities{})` not `w.RegisterActivity(a.MyMethod)`
|
|
6. **Forgetting to heartbeat** - Long-running activities need `activity.RecordHeartbeat(ctx, details)`
|
|
7. **Using `fmt.Println` in workflows** - Use `workflow.GetLogger(ctx)` for replay-safe logging
|
|
8. **Not setting Activity timeouts** - `StartToCloseTimeout` or `ScheduleToCloseTimeout` is required in `ActivityOptions`
|
|
|
|
## Writing Tests
|
|
|
|
See `references/go/testing.md` for info on writing tests.
|
|
|
|
## Additional Resources
|
|
|
|
### Reference Files
|
|
- **`references/go/patterns.md`** - Signals, queries, child workflows, saga pattern, etc.
|
|
- **`references/go/determinism.md`** - Determinism rules, workflowcheck tool, safe alternatives
|
|
- **`references/go/gotchas.md`** - Go-specific mistakes and anti-patterns
|
|
- **`references/go/error-handling.md`** - ApplicationError, retry policies, non-retryable errors
|
|
- **`references/go/observability.md`** - Logging, metrics, tracing, Search Attributes
|
|
- **`references/go/testing.md`** - TestWorkflowEnvironment, time-skipping, activity mocking
|
|
- **`references/go/advanced-features.md`** - Schedules, worker tuning, and more
|
|
- **`references/go/data-handling.md`** - Data converters, payload codecs, encryption
|
|
- **`references/go/versioning.md`** - Patching API (`workflow.GetVersion`), Worker Versioning
|
|
- **`references/python/determinism-protection.md`** - Information on **`workflowcheck`** tool to help statically check for determinism issues.
|