Files
temporalio__skill-temporal-…/references/java/determinism-protection.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.4 KiB

Java Determinism Protection

Overview

The Java SDK has no sandbox (only Python and TypeScript have sandboxing). Java relies on developer conventions and runtime replay detection to enforce determinism. A static analysis tool (temporal-workflowcheck) is available in beta.

Forbidden Operations in Workflows

The following are forbidden inside workflow code but are appropriate to use in activities.

// BAD: Non-deterministic operations in workflow code
Thread.sleep(1000);
UUID id = UUID.randomUUID();
double val = Math.random();
long now = System.currentTimeMillis();
new Thread(() -> doWork()).start();
CompletableFuture.supplyAsync(() -> compute());

// GOOD: Deterministic Workflow.* alternatives
Workflow.sleep(Duration.ofSeconds(1));
String id = Workflow.randomUUID().toString();
int val = Workflow.newRandom().nextInt();
long now = Workflow.currentTimeMillis();
Promise<Void> promise = Async.procedure(() -> doWork());
CompletablePromise<String> promise = Workflow.newPromise();

Static Analysis with temporal-workflowcheck

Warning: This tool is in beta.

temporal-workflowcheck scans compiled bytecode to detect non-deterministic operations in workflow code. It catches threading, I/O, randomization, system time access, and non-final static field access — including transitive violations through call chains.

Setup (Gradle)

Add the dependency as a compile-only check:

dependencies {
    implementation 'io.temporal:temporal-sdk:1.+'
    compileOnly 'io.temporal:temporal-workflowcheck:1.+'
}

See the Gradle sample for full task configuration.

Setup (Maven)

See the Maven sample for POM configuration.

Running Manually

Download the -all.jar from Maven Central (io.temporal:temporal-workflowcheck) and run:

java -jar temporal-workflowcheck-<version>-all.jar check <classpath-entries>

Suppressing False Positives

Use the @WorkflowCheck.SuppressWarnings annotation on methods:

@WorkflowCheck.SuppressWarnings(invalidMembers = "currentTimeMillis")
public long getCurrentMillis() {
    return System.currentTimeMillis();
}

Or use a .properties configuration file with --config <path> for third-party library false positives.

Convention-Based Enforcement

Java workflow code runs in a cooperative threading model where only one workflow thread executes at a time under a global lock. The SDK does not intercept or block non-deterministic calls. Instead, non-determinism is detected at replay time: if replayed code produces results that differ from the recorded history, the SDK throws a NonDeterministicException.

Use both temporal-workflowcheck (static, pre-deploy) and WorkflowReplayer (replay testing) to catch non-determinism before production.

Best Practices

  1. Run temporal-workflowcheck in CI to catch non-deterministic code statically
  2. Always use Workflow.* APIs instead of standard Java equivalents for time, randomness, UUIDs, sleeping, and threading
  3. Test all workflow code changes with WorkflowReplayer against recorded histories
  4. Keep workflows focused on orchestration logic; move all I/O and side effects into activities
  5. Avoid mutable static state shared across workflow instances