Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion references/core/determinism.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ Each Temporal SDK language provides a different level of protection against non-
- TypeScript: The TypeScript SDK runs workflows in an isolated V8 sandbox, intercepting many common sources of non-determinism and replacing them automatically with deterministic variants.
- Java: The Java SDK has no sandbox. Determinism is enforced by developer conventions — the SDK provides `Workflow.*` APIs as safe alternatives (e.g., `Workflow.sleep()` instead of `Thread.sleep()`), and non-determinism is only detected at replay time via `NonDeterministicException`. A static analysis tool (`temporal-workflowcheck`, beta) can catch violations at build time. Cooperative threading under a global lock eliminates the need for synchronization.
- Go: The Go SDK has no runtime sandbox. Therefore, non-determinism bugs will never be immediately appararent, and are usually only observable during replay. The optional `workflowcheck` static analysis tool can be used to check for many sources of non-determinism at compile time.
- .NET: The .NET SDK has no sandbox. It uses a custom TaskScheduler and a runtime EventListener to detect invalid task scheduling. Developers must use Workflow.* safe alternatives (e.g., Workflow.DelayAsync instead of Task.Delay) and avoid non-deterministic .NET Task APIs.
- .NET: The .NET SDK has no sandbox. It uses a custom TaskScheduler and a runtime EventListener to detect invalid task scheduling. Developers must use `Workflow.*` safe alternatives (e.g., Workflow.DelayAsync instead of Task.Delay) and avoid non-deterministic .NET Task APIs.

Regardless of which SDK you are using, it is your responsibility to ensure that workflow code does not contain sources of non-determinism. Use SDK-specific tools as well as replay tests for doing so.

Expand Down
1 change: 1 addition & 0 deletions references/dotnet/data-handling.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ The .NET SDK uses data converters to serialize/deserialize workflow inputs, outp
## Default Data Converter

The default converter handles:

- `null`
- `byte[]` (as binary)
- `Google.Protobuf.IMessage` instances
Expand Down
2 changes: 2 additions & 0 deletions references/dotnet/determinism-protection.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public class BadWorkflow
Many .NET `Task` APIs implicitly use `TaskScheduler.Default`, which breaks determinism. Here are the key rules:

**Do NOT use:**

- `Task.Run` — uses default scheduler. Use `Workflow.RunTaskAsync`.
- `Task.ConfigureAwait(false)` — leaves current context. Use `ConfigureAwait(true)` or omit.
- `Task.Delay` / `Task.Wait` / timeout-based `CancellationTokenSource` — uses system timers. Use `Workflow.DelayAsync` / `Workflow.WaitConditionAsync`.
Expand All @@ -36,6 +37,7 @@ Many .NET `Task` APIs implicitly use `TaskScheduler.Default`, which breaks deter
- `System.Threading.Semaphore` / `SemaphoreSlim` / `Mutex` — use `Temporalio.Workflows.Semaphore` / `Mutex`.

**Be wary of:**

- Third-party libraries that implicitly use `TaskScheduler.Default`
- `Dataflow` blocks and similar concurrency libraries with hidden default scheduler usage

Expand Down
9 changes: 9 additions & 0 deletions references/dotnet/dotnet.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@ Temporal workflows are durable through history replay. For details on how this w
## Quick Start

**Add Dependency:** Install the Temporal SDK NuGet package:

```bash
dotnet add package Temporalio
```

**Activities.cs** - Activity definitions (separate file for clarity):

```csharp
using Temporalio.Activities;

Expand All @@ -32,6 +34,7 @@ public class MyActivities
```

**GreetingWorkflow.workflow.cs** - Workflow definition:

```csharp
using Temporalio.Workflows;

Expand All @@ -49,6 +52,7 @@ public class GreetingWorkflow
```

**Worker (Program.cs)** - Worker setup:

```csharp
using Temporalio.Client;
using Temporalio.Worker;
Expand All @@ -69,6 +73,7 @@ await worker.ExecuteAsync();
**Start the worker:** Run `dotnet run` in the worker project.

**Starter (Program.cs)** - Start a workflow execution:

```csharp
using Temporalio.Client;

Expand All @@ -86,19 +91,22 @@ Console.WriteLine($"Result: {result}");
## Key Concepts

### Workflow Definition

- Use `[Workflow]` attribute on class
- Put any state initialization logic in the constructor of your workflow class to guarantee that it happens before signals/updates arrive. If your state initialization logic requires the workflow parameters, then add the `[WorkflowInit]` attribute and parameters to your constructor.
- Use `[WorkflowRun]` on the async entry point method
- Must return `Task` or `Task<T>`
- Use `[WorkflowSignal]`, `[WorkflowQuery]`, `[WorkflowUpdate]` for handlers

### Activity Definition

- Use `[Activity]` attribute on methods
- Can be sync or async
- Instance methods support dependency injection
- Static methods are also supported

### Worker Setup

- Connect client, create `TemporalWorker` with workflows and activities
- Use `AddWorkflow<T>()` and `AddAllActivities(instance)` or `AddActivity(method)`

Expand Down Expand Up @@ -181,6 +189,7 @@ See `references/dotnet/testing.md` for info on writing tests.
## Additional Resources

### Reference Files

- **`references/dotnet/patterns.md`** — Signals, queries, child workflows, saga pattern, etc.
- **`references/dotnet/determinism.md`** — Essentials of determinism in .NET
- **`references/dotnet/gotchas.md`** — .NET-specific mistakes and anti-patterns
Expand Down
1 change: 1 addition & 0 deletions references/dotnet/gotchas.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ public class GoodWorkflow
### Not Handling Activity Cancellation

Activities must **opt in** to receive cancellation. This requires:

1. **Heartbeating** — Cancellation is delivered via heartbeat
2. **Checking the cancellation token** — Token is triggered when heartbeat detects cancellation

Expand Down
1 change: 1 addition & 0 deletions references/dotnet/observability.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public class MyWorkflow
```

The workflow logger automatically:

- Suppresses duplicate logs during replay
- Includes workflow context (workflow ID, run ID, etc.)

Expand Down
2 changes: 2 additions & 0 deletions references/dotnet/patterns.md
Original file line number Diff line number Diff line change
Expand Up @@ -425,10 +425,12 @@ public class HandlerAwareWorkflow
## Activity Heartbeat Details

### WHY:

- **Support activity cancellation** — Cancellations are delivered via heartbeat; activities that don't heartbeat won't know they've been cancelled
- **Resume progress after worker failure** — Heartbeat details persist across retries

### WHEN:

- **Cancellable activities** — Any activity that should respond to cancellation
- **Long-running activities** — Track progress for resumability
- **Checkpointing** — Save progress periodically
Expand Down
1 change: 1 addition & 0 deletions references/dotnet/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ public async Task TestActivity()
```

The `ActivityEnvironment` provides:

- `Info` — Activity info, defaulted to basic values
- `CancellationTokenSource` — Token source for issuing cancellation
- `Heartbeater` — Callback invoked each heartbeat
Expand Down
6 changes: 6 additions & 0 deletions references/dotnet/versioning.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public class ShippingWorkflow
```

**How it works:**

- For new executions: `Patched()` returns `true` and records a marker in the Workflow history
- For replay with the marker: `Patched()` returns `true` (history includes this patch)
- For replay without the marker: `Patched()` returns `false` (history predates this patch)
Expand Down Expand Up @@ -207,6 +208,7 @@ var worker = new TemporalWorker(
```

**Configuration parameters:**

- `UseWorkerVersioning`: Enables Worker Versioning
- `DeploymentOptions`: Identifies the Worker Deployment Version (deployment name + build ID)
- Build ID: Typically a git commit hash, version number, or timestamp
Expand All @@ -223,6 +225,7 @@ public class StableWorkflow { /* ... */ }
```

**When to use PINNED:**

- Short-running workflows (minutes to hours)
- Consistency is critical (e.g., financial transactions)
- You want to eliminate version compatibility complexity
Expand All @@ -238,6 +241,7 @@ public class UpgradableWorkflow { /* ... */ }
```

**When to use AUTO_UPGRADE:**

- Long-running workflows (weeks or months)
- Workflows need to benefit from bug fixes during execution
- Migrating from traditional rolling deployments
Expand Down Expand Up @@ -269,6 +273,7 @@ var worker = new TemporalWorker(
**Blue-Green Deployments**

Maintain two environments and switch traffic between them:

1. Deploy new code to idle environment
2. Run tests and validation
3. Switch traffic to new environment
Expand All @@ -277,6 +282,7 @@ Maintain two environments and switch traffic between them:
**Rainbow Deployments**

Multiple versions run simultaneously:

- New workflows use latest version
- Existing workflows complete on their original version
- Add new versions alongside existing ones
Expand Down