A long-running customer workflow spanning payment, verification, notification and fulfilment must survive worker crashes and deploys mid-flow. Compare a hand-written saga with a durable-execution engine.
Show the full answer Hide the answer
What the hand-written saga actually requires
Writing this correctly means building, by hand: a persisted state machine per workflow instance; an idempotency guarantee on every step, since any step may be re-executed after a crash; a timer service for the waits, surviving restarts; compensation logic for every step, in reverse order, itself idempotent and itself able to fail; retry policies per step; visibility into where each instance is stuck; and a versioning story for instances in flight when the code changes.
That list is a workflow engine. Teams do not usually decide to build one; they arrive at one incrementally, and the incremental version is under-tested precisely in the failure paths that justify its existence.
What durable execution provides
The workflow is written as ordinary sequential code — call payment, await verification, sleep three days, send notification — and the engine persists the history of every step's result. After a crash the engine replays the history to reconstruct local state, then continues from the first unexecuted step. The process crashing becomes an implementation detail rather than an application concern.
The constraint that this imposes
Workflow code must be deterministic, because replay must reproduce the same decisions. That rules out
now(), random numbers, direct network or database calls, iteration over unordered collections, and dependence
on the local clock. All non-determinism moves into activities, whose results are recorded in history and
replayed rather than re-executed.
This constraint is the whole trade. It is teachable and it is a real change in how the code is written, and
it is routinely underestimated — the first production bug is almost always a Map iteration order or a
Date.now() that someone missed.
Versioning in-flight workflows
The genuinely hard problem, and the one that decides the outcome. A workflow instance started three weeks ago replays against today's code, so any change to the sequence of steps breaks replay. Engines provide explicit version gates so that old instances take the old path and new ones take the new — and this must be planned for before the first long-running workflow ships, because retrofitting it is painful.
Hand-rolled sagas have the identical problem and usually no mechanism at all, so the resolution is a manual database migration of stuck instances.
The decision
Use durable execution when workflows are long-lived (hours to months), span multiple services, must survive deploys, and where being stuck invisibly is expensive — payments, onboarding, KYC, provisioning, fulfilment.
Do not use it for a three-step synchronous operation inside one service, where a transaction plus an outbox is simpler and has no determinism constraint. And do not use it merely to avoid writing a state machine: it is an operational dependency with its own scaling, storage growth and failure modes.
The honest summary: you are choosing between an engine somebody else has debugged and one you will debug yourself, in the failure paths, in production.