Workflow replay preserves orchestration state; idempotency protects external effects after an ambiguous activity outcome.
Idempotent Durable Activity
Durable orchestration records decisions, while idempotency protects effects outside the workflow engine.
export async function chargeOrder(input: ChargeInput) {
const key = 'charge:' + input.orderId
const prior = await operations.find(key)
if (prior?.status === 'completed') return prior.result
// The provider must persist the same key with the effect.
const result = await payments.charge({
amount: input.amount,
idempotencyKey: key,
signal: AbortSignal.timeout(10_000),
})
await operations.complete(key, result)
return result
}
// Validation and authorization errors must be configured non-retryable.Invariant: One logical activity command produces at most one external business effect across every retry.
Use when: A workflow engine may retry an external side effect after losing its completion acknowledgement.
Why this boundary matters
A provider may commit an effect before the worker loses its acknowledgement. Replay cannot infer external state from that missing response.
Failure policy
| Boundary | Action |
|---|---|
| First command identity | Execute and durably record the provider outcome |
| Known completed identity | Return the recorded result |
| Transient provider failure | Retry within the activity lifetime |
| Validation or authorization failure | Mark terminal and do not retry |
| Commit acknowledgement missing | Query or reconcile before repeating the effect |
Trade-offs
Durable workflows remove orchestration bookkeeping but add replay constraints, history growth, and platform operations. Activity idempotency remains application-specific and can require provider support or reconciliation.
Decision rule: Use a durable activity when work must survive process loss; require stable command identity wherever the activity can change external state.
Further reference
Browse all engineering snippets · Read the architecture guide