Skip to content

Add deterministic NewGuid() to OrchestrationContext - #124

Open
kaibocai (kaibocai) wants to merge 1 commit into
mainfrom
feature/add-newguid-orchestration-context
Open

Add deterministic NewGuid() to OrchestrationContext#124
kaibocai (kaibocai) wants to merge 1 commit into
mainfrom
feature/add-newguid-orchestration-context

Conversation

@kaibocai

Copy link
Copy Markdown
Member

Summary

Adds a replay-safe, deterministic UUID generation method to OrchestrationContext, closing the gap with the .NET Durable Task SDK.

Algorithm

Uses UUID v5 (SHA-1, RFC 4122) with the same namespace (9e952958-5e33-4daf-827f-2fa12937b875) and name format ({instanceId}_{timestamp}_{counter}) as the .NET implementation.

Cross-SDK alignment details

  • Timestamp formatted with exactly 7 fractional digits to match .NET DateTime.ToString("o")
  • Nanoseconds truncated to 100ns (tick) precision to match .NET DateTime behavior
  • Counter starts at 0 per context, incremented after each call
  • Produces identical UUIDs to the .NET SDK for the same inputs

Usage

funcMyOrchestrator(ctx*task.OrchestrationContext) (any, error) {
id:=ctx.NewGuid() // deterministic, replay-safe UUID// use id as correlation ID, idempotency key, etc.
}

Changes

FileChange
task/orchestrator.gouuid import, namespace constant, format constant, newGuidCounter field, NewGuid() method
task/orchestrator_test.go9 unit tests (determinism, uniqueness, golden values, UUID v5 compliance, .NET format alignment, nanosecond truncation, counter reset)
tests/orchestrations_test.go1 integration test (replay determinism through activity calls)

Test Coverage

TestVerifies
DeterministicSame inputs → same GUIDs
Unique100 consecutive calls all unique
DifferentInstancesInstance ID isolation
DifferentTimesTimestamp isolation
NanosecondTruncationSub-100ns truncated (.NET parity)
TimestampFormat7 fractional digits + Z
GoldenValuesHardcoded regression test
UUIDv5PropertiesVersion=5, Variant=RFC4122
CounterResetOnNewContextFresh context = counter at 0
Integration Test_NewGuidEnd-to-end replay with activities

Related

Closes gap identified in cross-SDK alignment analysis: .NET has TaskOrchestrationContext.NewGuid() but Go had no equivalent, forcing users to use non-deterministic uuid.New() which breaks replay.

Add a replay-safe, deterministic UUID generation method to
OrchestrationContext, aligned with the .NET Durable Task SDK.
Algorithm: UUID v5 (SHA-1, RFC 4122) using the same namespace
(9e952958-5e33-4daf-827f-2fa12937b875) and name format
(instanceId_timestamp_counter) as the .NET implementation.
Key details:
- Timestamp formatted with exactly 7 fractional digits to match
.NET DateTime.ToString("o")
- Nanoseconds truncated to 100ns (tick) precision for .NET parity
- Counter starts at 0 per context, incremented after each call
- Produces identical UUIDs to .NET SDK for same inputs
Tests: 9 unit tests + 1 integration test covering determinism,
uniqueness, .NET format alignment, golden value regression,
UUID v5 compliance, and replay safety.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a replay-safe, deterministic GUID generator to the orchestration runtime to match Durable Task .NET’s TaskOrchestrationContext.NewGuid() behavior and prevent non-deterministic UUID usage during replay.

Changes:

  • Add OrchestrationContext.NewGuid() using UUID v5 with .NET-aligned namespace + timestamp formatting + per-context counter.
  • Add unit tests covering determinism, uniqueness, formatting, golden values, and UUID v5 properties.
  • Add an integration test ensuring GUID determinism across replays when passing values through activities.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

FileDescription
task/orchestrator.goAdds deterministic GUID namespace/format constants, a counter field, and NewGuid() implementation.
task/orchestrator_test.goAdds focused unit tests validating determinism, alignment, and regression (golden) outputs.
tests/orchestrations_test.goAdds end-to-end replay determinism coverage via activity round-trips.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment threadtask/orchestrator.go
Comment on lines +454 to +461
// This uses UUID v5 (SHA-1) per RFC 4122, matching the algorithm used by the .NET Durable Task SDK.
func (ctx *OrchestrationContext) NewGuid() uuid.UUID {
// Truncate to 100-nanosecond (tick) precision to match .NET DateTime behavior,
// then format with exactly 7 fractional digits to match .NET's ToString("o").
truncatedTime := ctx.CurrentTimeUtc.Truncate(100 * time.Nanosecond)
name := fmt.Sprintf("%s_%s_%d", ctx.ID, truncatedTime.Format(dotnetDateTimeFormat), ctx.newGuidCounter)
ctx.newGuidCounter++
return uuid.NewSHA1(deterministicGuidNamespace, []byte(name))
Comment threadtask/orchestrator.go
pendingExternalEventTasks map[string]*list.List
saveBufferedExternalEvents bool

newGuidCounter int
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@kaibocai