You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Document replay-safe Workflow APIs per SDK (#5054)
* Document replay-safe Workflow APIs per SDK
Add a heading per topic under the Workflow logic requirements section so
readers can find the replay-safe alternative for what they need.
- Ruby and .NET: add Logging, Random/UUIDs, Current time, and Detecting
replay sections. Neither page previously named any replacement API.
- Go: add the same four sections. Go has no built-in seeded random or
UUID helper, so that section shows the Side Effect approach.
- Java: add the same four sections, and point the existing
"non-deterministic functions" bullet at the new one.
- TypeScript: lead the Random/UUIDs section with the SDK's own uuid4()
instead of the uuid npm package.
Each documented API was run against a dev server and its history replayed
through the SDK replayer.
* Remove counter-examples from Random numbers sections
Show only the recommended API. Also removes the pre-existing bad example
from the Python page.
* Use WorkflowUnsafe.isReplaying() in Java replay detection
Workflow.isReplaying() is deprecated in favor of the unsafe package
method, which also matches the other SDKs.
Use [`Workflow.UtcNow`](https://dotnet.temporal.io/api/Temporalio.Workflows.Workflow.html#Temporalio_Workflows_Workflow_UtcNow)
127
+
instead of `DateTime.Now` or `DateTime.UtcNow`. It returns the time of the last Workflow Task, which is consistent
128
+
across replays:
129
+
130
+
```csharp
131
+
varcurrentTime=Workflow.UtcNow;
132
+
```
133
+
134
+
To wait, use `Workflow.DelayAsync` instead of `Task.Delay` or `Thread.Sleep`.
135
+
136
+
### Detecting replay (advanced)
137
+
138
+
Use [`Workflow.Unsafe.IsReplaying`](https://dotnet.temporal.io/api/Temporalio.Workflows.Workflow.Unsafe.html#Temporalio_Workflows_Workflow_Unsafe_IsReplaying)
139
+
to guard code that should only run on the first execution, such as emitting metrics or sending external notifications
140
+
from an [Interceptor](/develop/dotnet/workers/interceptors).
141
+
142
+
:::caution
143
+
144
+
Never use this to affect Workflow business logic. Branching on replay status breaks determinism.
145
+
146
+
:::
147
+
148
+
```csharp
149
+
if (!Workflow.Unsafe.IsReplaying)
150
+
{
151
+
EmitMetric("workflow_started", 1);
152
+
}
153
+
```
154
+
155
+
If your goal is to always take action when something new is happening, check that
Copy file name to clipboardExpand all lines: docs/develop/java/workflows/basics.mdx
+68-1Lines changed: 68 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -253,7 +253,7 @@ When defining Workflows using the Temporal Java SDK, the Workflow code must be w
253
253
The following constraints apply when writing Workflow Definitions:
254
254
255
255
- Do not use mutable global variables in your Workflow implementations. This will ensure that multiple Workflow instances are fully isolated.
256
-
- Workflow code must be deterministic. If you need to call non-deterministic functions (such as non-seeded random or `UUID.randomUUID()`) directly from the Workflow code, the Temporal SDK provides specific API for calling non-deterministic code in your Workflows.
256
+
- Workflow code must be deterministic. If you need to call non-deterministic functions (such as non-seeded random or `UUID.randomUUID()`) directly from the Workflow code, the Temporal SDK provides replay-safe replacements. See [Random numbers and UUIDs](#random-numbers-and-uuids).
257
257
- For operations like calling external APIs, invoking LLMs, querying databases, or performing I/O, use Activities. Activities run outside Workflow replay and are retried reliably.
258
258
- Use Temporal-provided functions instead of that rely on system time. For example, use only `Workflow.currentTimeMillis()` to get the current time inside a Workflow.
259
259
- Use `Async.function` or `Async.procedure`, provided by the Temporal SDK, to execute code asynchronously instead of native Java `Thread` or any other multi-threaded classes like `ThreadPoolExecutor`.
@@ -265,4 +265,71 @@ The following constraints apply when writing Workflow Definitions:
265
265
- Do not access configuration APIs directly from a Workflow because changes in the configuration might affect a Workflow Execution path. Instead, pass it as an argument to a Workflow function or use an Activity to load it.
266
266
- Use `DynamicWorkflow` when you need a default Workflow that can handle all Workflow Types that are not registered with a Worker. A single implementation can implement a Workflow Type which by definition is dynamically loaded from some external source. All standard `WorkflowOptions` and determinism rules apply to Dynamic Workflow implementations.
267
267
268
+
The SDK provides replay-safe alternatives for common needs.
269
+
270
+
### Logging
271
+
272
+
Use [`Workflow.getLogger()`](https://www.javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/workflow/Workflow.html)
273
+
instead of `System.out.println` or a logger you create yourself. The SDK logger skips log messages during replay to
0 commit comments