Replay
The graph engine tracked execution with tokens. The durable runtime tracks facts. A restart loads the run and its history, invokes the same versioned workflow, and replays until the next unresolved await.
How Replay Works
- Load the run, ordered history, and commands.
- Verify code, version, and digest.
- Invoke the workflow from its first line.
- Each completed durable await returns its recorded result immediately.
- The first unresolved await appends a command and history event, then marks the run
blocked.
The function may execute from the top many times. Service calls and human work are not repeated. Activities receive the same idempotency key for the same attempt.
What Makes Replay Safe
| Allowed in workflow code | Forbidden |
|---|---|
if / switch over input or recorded results | Network or database calls |
| Typed local values | DateTime.now(), random IDs |
workflow.parallel / race / quorum | Future.wait, unregistered futures |
| Stable operation IDs | Hidden mutable globals |
A missing binding path fails the decision before new work is scheduled.
Interrupted Decisions
If a server dies between event commit and decision commit, recovery finds running runs with decision_pending and drives them again. Optimistic revision prevents two deciders from committing from the same history position.
Late Completions
Only the current fenced command owner may report completion. After a race or quorum resolves, loser cancellation commits in the same transaction. A late loser completion is rejected.