mirror of
https://github.com/temporalio/skill-temporal-developer.git
synced 2026-09-14 13:52:58 +08:00
e16c9b808a
* 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
2.9 KiB
2.9 KiB
Go SDK Determinism
Overview
The Go SDK has NO runtime sandbox (unlike Python/TypeScript). Workflows must be deterministic for replay, and determinism is enforced entirely by developer convention and optional static analysis via the workflowcheck tool (see references/go/determinism-protection.md).
Why Determinism Matters: History Replay
Temporal provides durable execution through History Replay. When a Worker restores workflow state, it re-executes workflow code from the beginning. This requires the code to be deterministic. See references/core/determinism.md for a deep explanation.
Forbidden Operations
Do not use any of the following in workflow code:
- Native goroutines (
go func()) -- useworkflow.Go()instead - Native channels (
chan, send, receive,rangeover channel) -- useworkflow.Channelinstead - Native
select-- useworkflow.Selectorinstead time.Now()-- useworkflow.Now(ctx)insteadtime.Sleep()-- useworkflow.Sleep(ctx, duration)insteadmath/randglobal (e.g.,rand.Intn()) -- useworkflow.SideEffectinsteadcrypto/rand.Reader-- use an activity insteados.Stdin/os.Stdout/os.Stderr-- useworkflow.GetLogger(ctx)for logging- Map range iteration (
for k, v := range myMap) -- sort keys first, then iterate - Mutating global variables -- use local state or
workflow.SideEffect - Anonymous functions as local activities -- the name is derived from the function and will be non-deterministic across replays; always use named functions for local activities
Safe Builtin Alternatives
| Instead of | Use |
|---|---|
go func() { ... }() |
workflow.Go(ctx, func(ctx workflow.Context) { ... }) |
chan T |
workflow.NewChannel(ctx) / workflow.NewBufferedChannel(ctx, size) |
select { ... } |
workflow.NewSelector(ctx) |
time.Now() |
workflow.Now(ctx) |
time.Sleep(d) |
workflow.Sleep(ctx, d) |
rand.Intn(100) |
workflow.SideEffect(ctx, func(ctx workflow.Context) interface{} { return rand.Intn(100) }) |
uuid.New() |
workflow.SideEffect or pass as activity result |
log.Println(...) |
workflow.GetLogger(ctx).Info(...) |
Testing Replay Compatibility
Use worker.WorkflowReplayer to verify code changes are compatible with existing histories. See the Workflow Replay Testing section of references/go/testing.md
Best Practices
- Run
workflowcheck ./...in CI to catch non-deterministic code early - Always use
workflow.*APIs instead of native Go concurrency and time primitives - Move all I/O operations (network, filesystem, database) into activities
- Sort map keys before iterating if you must iterate over a map in workflow code
- Use
workflow.GetLogger(ctx)instead offmt.Printlnorlog.Printlnfor replay-safe logging - Keep workflow code focused on orchestration; delegate non-deterministic work to activities
- Test with replay after making changes to workflow definitions