distributedsystem softwareengineering systemdesign

Durable Execution is a programming model where a workflow’s execution progress is persisted to durable storage, independent of the process running it, so a crash means resume, not restart.

Core Problem

  • Single Machine, Single function -> Crash , just rerun.
    • No side effects, no harm (comparing Distributed systems)
  • Distributed workflow (multiple services) → crash mid-way is dangerous, because some steps already had real-world effects (charged a card, sent an email) that can’t be undone by re-running code.

failure in distributed systems is partial, not binary. Some steps succeed, some fail — system must reconcile an inconsistent state.

async function signup(user) {
  const charge = await Payment.create(user.card, 10); // âś… succeeds
  // đź’Ą crash here
  const account = await Account.create(user);
  await Access.grant(account, charge);
}

Rerun from top → double charge. Skip ahead → maybe free access. Both bad.

Questions every distributed workflow must answer

QuestionWhy it’s hard
Which steps already ran?No shared memory if process dies
Is this step safe to retry?Idempotency must be enforced manually otherwise
How do we undo a step that already happened?Compensation / saga logic(The Saga Pattern)
Where do timers/long waits live if the process restarts?Can’t rely on in-memory timers
Without durable execution, this glue code (retries, idempotency keys, saga compensation, timeouts) often outweighs the actual business logic.

Solution

Persist workflow progress to durable storage, not to the memory of one running process. (Separate progress from process)

Mechanics (how replay actually works):

  1. Record history — every step’s input/output is written to durable storage before moving on.
  2. Replay on recovery — a new process re-runs the code from the start, but skips already-completed steps by reading their recorded results instead of re-executing them.
  3. Determinism required — workflow logic must produce the same path given the same inputs, or replay can’t rebuild state correctly. Non-deterministic values (random, time, external calls) must be captured as recorded facts.
  4. Time becomes durable — timers/delays survive crashes natively; no external cron hack needed.

Complexity doesn’t disappear — it moves into the runtime, built once and tested thoroughly instead of reinvented per service.

PatternManual approachDurable execution approach
RetriesCustom retry loops everywhereBuilt into runtime, tied to history
Sagas / compensationHand-written rollback logicOrchestrated automatically
Long timers / cronExternal schedulersNative durable timers
State machinesCustom “where am I” persistenceImplicit — history is the state
IdempotencyIdempotency keys threaded through APIsSteps recorded once, can’t double-fire on replay

Who uses it / what tools implement it

  • Used at: Stripe, Netflix, HashiCorp, Datadog (per Temporal’s writeup)
  • Engines:
    • Temporal - most established, SDK + worker model, full event history
    • Restate - lighter, HTTP-native ergonomics
    • AWS Step Functions / Azure Durable Functions - state-machine style
    • Inngest / Conductor (Orkes) - event-triggered / orchestration platforms

The question today isn’t whether to use durable execution for complex multi-step workflows, but which engine fits your team’s operational maturity and language stack.


AWS Lambda Durable Function