Files
Donald Pinckney b5719bc143 PR Tracking Initial Release (#4)
* 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>
2026-03-19 17:36:15 -04:00

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.