Conclusion
A Saga replaces one distributed ACID transaction with an ordered chain of local transactions — each service commits its own database independently — and pairs every forward step with a compensating transaction that semantically undoes it, so when a later step fails the chain runs its compensations backward to return the system to a consistent state without ever holding a cross-service lock.
The one trace to remember
This capstone earns its place by fixing the trace in your head. Take the order-and-inventory example from the Java lesson, extended with the payment step from the worked orchestration example. Customer places order #4471: 3 units of SKU KB-84, total $59. Watch payment fail on the third step and the saga walk itself back:
| # | Step | Local commit | State after |
|---|---|---|---|
| T1 | OrderService.createOrder | insert Order #4471 = PENDING | Order visible, PENDING |
| T2 | InventoryService.reserve(KB-84, 3) | stock 12 → 9 | 3 units held for #4471 |
| T3 | PaymentService.charge($59) | card declined — FAIL | no charge; saga must abort |
| C2 | InventoryService.release(KB-84, 3) | stock 9 → 12 | hold removed |
| C1 | OrderService.cancelOrder(#4471) | status → CANCELLED | system consistent again |
No two-phase lock ever spanned the three services. Between T2 and C2 the system was inconsistent but recoverable — 3 units were reserved against an order that would never pay. That window is the price Saga charges for availability, and every pitfall below lives inside it.
Orchestration vs choreography — two ways to run the same chain
The module showed both coordination styles. In orchestration a central saga orchestrator issues commands ("reserve", then "charge", then "ship") and tracks which step is live. In choreography there is no coordinator: each service emits an event (InventoryReserved) and the next service listens and reacts. Correcting a common myth — choreography does not reduce communication overhead. It removes the central coordinator, not the messages; the same events still flow, and the total chatter often rises because every service must subscribe to and interpret others' events. What choreography actually trades is a central point of control for emergent, harder-to-trace flow.
| Orchestration | Choreography | |
|---|---|---|
| Control flow | Explicit, in one place | Emergent from events |
| "What step are we on?" | Query the orchestrator | Reconstruct from event log — hard |
| Main cost | Orchestrator to build/operate; can bloat into a god-service | Cyclic event dependencies; no single view of progress |
| Coupling | Services coupled to orchestrator | Services coupled to each other's events |
Pitfalls
- Non-idempotent compensations. If C2 runs twice (a retry after a timeout that actually succeeded), stock jumps 9 → 12 → 15 — phantom inventory. Compensations must be idempotent: key them by saga id so a repeat is a no-op.
- The compensation itself fails. C1 can throw too. There is no compensation-for-a-compensation, so failed compensations need retry-with-backoff plus a dead-letter queue and an alert — a stuck saga is an operational incident, not a caught exception.
- No isolation (the real cost). Between T2 and C2, 3 units are reserved against an order that will die. Another customer's read sees depleted stock — a dirty read Saga cannot prevent. Countermeasures are application-level: semantic locks, re-reads, or a PENDING flag other transactions respect.
- Orchestrator crash mid-saga. If the orchestrator dies after T2 with no durable saga log, on restart it cannot know C2 is owed — the reservation leaks forever. Persist saga state on every transition.
- Irreversible steps ordered too early. You cannot compensate a shipped package or a sent email. Put non-compensatable actions last (after the "pivot transaction"), so everything reversible commits before anything permanent happens.
When to use Saga — and when not to
Reach for Saga when a business operation must span several services' databases, runs at high throughput or over a long duration, and your datastores/HTTP services don't support distributed (XA) transactions — which is almost always true for modern microservices.
The named alternative is two-phase commit (2PC / distributed transaction). A coordinator asks every participant to prepare (lock resources, promise it can commit) and then commit. That buys true atomic isolation — no one sees the #4471 reservation until the whole thing succeeds — but the resources stay locked for the full round trip, a coordinator failure freezes every participant mid-prepare, it doesn't scale to high volume, and most cloud datastores simply don't offer XA.
- Choose Saga when you value availability and throughput, the operation is long-lived or cross-service, and you can tolerate temporary inconsistency plus the work of writing compensations.
- Prefer 2PC when participants are few, all support XA, volume is low, and strict isolation is a hard requirement (some financial ledgers).
- Within Saga, choose orchestration when the flow has many steps, branching, or needs audit/visibility; prefer choreography when there are only a couple of steps, teams want autonomy, and you are already event-driven — accepting that tracing the flow gets harder.
Takeaways
- Saga = local commits + compensations, chosen because it avoids cross-service locks; the price is lost isolation (dirty reads) and eventual, not atomic, consistency.
- Compensations are the hard part: they must be idempotent, durable, and themselves retryable — and irreversible steps must be ordered last.
- Orchestration vs choreography is a visibility-vs-autonomy trade, not a communication-overhead one; choreography removes the coordinator, not the messages.
- Saga beats 2PC for scalable microservices precisely because it refuses to hold locks — reach for 2PC only when few participants support XA and strict isolation is mandatory.
Re-authored and deepened for this guide. Draws on Chris Richardson, Microservices Patterns (Manning, 2018) and microservices.io (Saga, Orchestration/Choreography, and the semantic-lock / pivot-transaction countermeasures); Hector Garcia-Molina & Kenneth Salem, "Sagas" (ACM SIGMOD, 1987) for the original long-lived-transaction model; and the Java order/inventory example from lesson 057 extended with the payment step from the worked orchestration example (061). Corrects the earlier recap, which mis-described the worked example as a bank transfer and claimed choreography lowers communication overhead.
🤖 Don't fully get this? Learn it with Claude
Stuck on Conclusion? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.
Build the mental picture, not memorization.
I just read a lesson on **Conclusion** (System Design) and want to truly understand it. Explain Conclusion from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Socratic — adapts to where you're stuck.
Teach me **Conclusion** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Active recall exposes what you missed.
Quiz me on **Conclusion** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Intuition + hook + flashcards for long-term memory.
Help me remember **Conclusion** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.