Files
temporalio__skill-temporal-…/references/go/determinism.md
Donald Pinckney 44eba4e91c Add .NET SDK support to temporal-developer skill (#39)
* Add .NET reference files for temporal-developer skill

Created 11 .NET reference files covering: dotnet.md (overview/quick start),
patterns.md, determinism.md, determinism-protection.md, error-handling.md,
testing.md, versioning.md, observability.md, data-handling.md, gotchas.md,
and advanced-features.md. Follows Python/TypeScript patterns with .NET-specific
content for Task determinism, CancellationToken, dependency injection, etc.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix .NET alignment issues from self-review

- dotnet.md: Reduce Determinism Rules section to brief cross-reference
  (was duplicating determinism.md content)
- patterns.md: Add ParentClosePolicy to Child Workflows example
- gotchas.md: Add missing "Heartbeat Timeout Too Short" subsection
- versioning.md: Add missing Key Concepts, Deployment Strategies,
  Query Filters, PINNED/AUTO_UPGRADE guidance, CLI examples
- advanced-features.md: Add worker-level heading for exception types

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix .NET correctness issues from verification pass

- patterns.md: Fix cancellation pattern to use official
  TemporalException.IsCanceledException(e) with detached CancellationTokenSource
- advanced-features.md: Fix DI hosting example to use official
  AddHostedTemporalWorker(clientTargetHost:, clientNamespace:, taskQueue:) pattern

Verified against official SDK README, API docs, and temporal-docs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Update supported language references to include .NET

- SKILL.md: Add "Temporal .NET" and "Temporal C#" trigger phrases,
  update overview to mention .NET, add .NET entry in getting started
- core/determinism.md: Add .NET entry in SDK Protection Mechanisms

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Edits to advanced features

* edits to determinism protection, and move the .editorconfig section

* missed one

* edit determinism.md

* edit error-handling.md

* edit gotchas.md

* edit patterns.md

* edit versioning.md

* edit observability.md

* fix metrics

* self-review round 1

* minor correctness fixed

* Update references/dotnet/patterns.md

Co-authored-by: Justin Anderson <44687433+jmaeagle99@users.noreply.github.com>

* address comments, clarify reference to earlier code snippet

* clarify that operations are forbidden IN WORKFLOWS

* cleanup workflow cancellation handling example

* add task token retrieval comment

* update .net requirements

* Fix propagation of workflow cancellation

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Justin Anderson <44687433+jmaeagle99@users.noreply.github.com>
2026-04-17 14:28:02 -04:00

3.0 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 in Workflows

Do not use any of the following in workflow code (they are appropriate to use in activities):

  • Native goroutines (go func()) -- use workflow.Go() instead
  • Native channels (chan, send, receive, range over channel) -- use workflow.Channel instead
  • Native select -- use workflow.Selector instead
  • time.Now() -- use workflow.Now(ctx) instead
  • time.Sleep() -- use workflow.Sleep(ctx, duration) instead
  • math/rand global (e.g., rand.Intn()) -- use workflow.SideEffect instead
  • crypto/rand.Reader -- use an activity instead
  • os.Stdin / os.Stdout / os.Stderr -- use workflow.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

  1. Run workflowcheck ./... in CI to catch non-deterministic code early
  2. Always use workflow.* APIs instead of native Go concurrency and time primitives
  3. Move all I/O operations (network, filesystem, database) into activities
  4. Sort map keys before iterating if you must iterate over a map in workflow code
  5. Use workflow.GetLogger(ctx) instead of fmt.Println or log.Println for replay-safe logging
  6. Keep workflow code focused on orchestration; delegate non-deterministic work to activities
  7. Test with replay after making changes to workflow definitions