Saga
Coordinate a multi-service transaction with compensations instead of a distributed lock.
By the end of this lesson, model a cross-service workflow as a saga with compensating actions.
A business process spanning services — place order, reserve inventory, charge payment, schedule shipping — can't use a single ACID transaction across databases. A saga models it as a sequence of local transactions, each with a compensating action that undoes it if a later step fails. There's no global lock; you get eventual consistency with explicit rollback logic.
First, see the whole system. Then we’ll open it up.
Steps and compensations
- Steps run forward: reserve inventory, charge payment, schedule shipping.
- If a step fails, compensations run in reverse: refund payment, release inventory.
flowchart LR s1[Reserve inventory] --> s2[Charge payment] s2 --> s3[Schedule shipping] s3 -.fail.-> c2[Refund payment] c2 --> c1[Release inventory]
Two coordination styles: orchestration (a central coordinator tells each service what to do next — easier to follow and monitor, but a central component) and choreography (services react to each other's events — decoupled, but the workflow is emergent and harder to trace). Every step and compensation must be idempotent, since steps are retried.
This is where the abstraction starts leaking.
A saga is not a rollback. Once you've charged a card and sent a confirmation email, you can't pretend it didn't happen — you *compensate* (refund, send a correction). Some effects aren't cleanly reversible, which is why sagas force you to think about real-world compensations, not database undo.
Sagas give you cross-service workflows without distributed locks (better availability and autonomy) at the cost of only eventual consistency and hand-written compensation logic. A distributed 2PC transaction gives stronger consistency but poor availability and tight coupling.
How does a saga 'undo' a completed step?
With a compensating action that semantically reverses it (e.g., refund a charge) — not a database rollback, since the step already committed.