abort-signal-timeout-in-workflow
Error
Why this happens
AbortSignal.timeout() creates a signal that aborts after a real-time delay using an internal timer. Workflow functions must be deterministic to support replay: they run the same code multiple times during the workflow's lifecycle, using the event log to resume execution to the correct point.
Real-time timers break this determinism because:
- On the first execution, the timer might fire after 10 seconds.
- On replay, the timer would fire again, but the event log may have already advanced past that point.
- The timer's behavior depends on wall-clock time, which varies between executions.
How to fix
Use sleep() with an AbortController to create a deterministic timeout that cancels in-flight work:
Before (incorrect):
After (correct):
The sleep() and AbortController pattern is the durable equivalent of AbortSignal.timeout(). The sleep is recorded in the event log, so it replays deterministically. If fetchData finishes within 10 seconds, you get the response. Otherwise, the timer calls controller.abort(), fetch rejects with an AbortError, and the step's failure propagates to the workflow as a FatalError (no retries because the abort is intentional cancellation).
AbortSignal.timeout() works normally inside step functions, since steps have full Node.js runtime access and are not replayed.
Related
- Cancellation: Patterns for canceling in-flight work
sleep()API Reference: Durable sleep primitive- Workflows and Steps: Why workflow functions must be deterministic
setTimeoutin Workflow: Similar restriction onsetTimeout