Tip
Workflow code runs in a shared worker process -- modifying global variables, singletons, or shared maps creates race conditions and breaks determinism on replay.
A Temporal worker runs many workflow executions concurrently in the same process. When workflow code writes to a global variable, every concurrent execution races to read and write the same memory without synchronization. On replay, the global state is in a completely different condition than it was during the original execution, causing non-determinism errors.
modifying_shared_state_in_workflow_code/workflow.go
// BAD: shared mutable state
var processedCount int
func MyWorkflowV1(ctx workflow.Context) error {
processedCount++ // Data race! Non-deterministic on replay!
if processedCount > 100 {
if err := workflow.ExecuteActivity(ctx, AlertActivity).Get(ctx, nil); err != nil {
return err
}
}
// ...
return nil
}modifying_shared_state_in_workflow_code/workflow.go
// GOOD: local state
func MyWorkflowV2(ctx workflow.Context) error {
processedCount := 0 // Local to this workflow execution
_ = processedCount
// ...
return nil
}Keep all workflow state local to the workflow function. Use activities for anything that needs to interact with external or shared state (databases, caches, counters). Be cautious with injected dependencies -- a shared logger with mutable state or a shared cache can cause the same problems if the workflow modifies that shared object.