Introduction

Every booking you've ever made online is secretly a chain of promises. Reserve a flight. Charge a card. Notify the airline. Update loyalty points. If any link breaks, all the earlier links must unwind — cleanly, without leaving you charged for a seat you don't have.

The classical answer is an ACID transaction: wrap everything in one big lock, commit once, rollback on failure. That works perfectly inside a single database. But once your workflow crosses service boundaries — an inventory service, a payment service, a notification service — holding one lock for seconds or minutes becomes a bottleneck, a deadlock risk, and often simply impossible.

Hector Garcia-Molina and Kenneth Salem described the solution in their 1987 paper: a saga. Break the long-running operation into a sequence of smaller local transactions, each of which commits immediately. If a later step fails, run compensating transactions in reverse order — each one undoing the effect of the step before it. No global lock ever held; eventual consistency guaranteed.

The pattern is so fundamental that every major cloud architecture guide lists it. Understanding it means understanding how the systems behind flights, hotel bookings, and e-commerce orders actually stay sane.

Try It: Roll Back a Saga

Below is a four-step booking saga: reserve a seat, charge the card, notify the airline, and award loyalty points. Each step commits locally. Press Run saga to advance through the steps one by one. At any point, press Inject failure to simulate a step crashing — and watch the saga automatically execute the compensating transactions in reverse to undo all earlier work.

<!-- {{c_html_root}} -->
<div class="saga-app">
  <p class="hint">{{hint_para}}</p>
  <div id="steps-list" class="steps-list"></div>
  <div class="status-bar" id="status-bar"></div>
  <div class="btns">
    <button id="btn-run" type="button">{{btn_run}}</button>
    <button id="btn-fail" type="button" class="danger">{{btn_fail}}</button>
    <button id="btn-reset" type="button" class="ghost">{{btn_reset}}</button>
  </div>
</div>
/* {{c_css_root}} */
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; color: #222; margin: 0; }
.saga-app { padding: .4rem 0; }
.hint { font-size: .87rem; color: #444; margin: 0 0 .8rem; line-height: 1.45; }
.steps-list { display: flex; flex-direction: column; gap: 6px; margin-bottom: .8rem; }
.step { display: flex; align-items: center; gap: 10px; padding: .5rem .75rem;
        border-radius: 8px; border: 1.5px solid #cdd9e3; background: #f4f7fa;
        font-size: .9rem; transition: all .25s; }
.step .icon { width: 22px; text-align: center; font-size: 1.1rem; flex-shrink: 0; }
.step .label { flex: 1; font-weight: 600; }
.step .comp { font-size: .78rem; color: #888; margin-left: auto; white-space: nowrap; }
/* {{c_state_pending}} */
.step.pending  { background: #f4f7fa; border-color: #cdd9e3; }
/* {{c_state_running}} */
.step.running  { background: #fff8e1; border-color: #f0c040; }
/* {{c_state_done}} */
.step.done     { background: #e8f5e9; border-color: #66bb6a; }
/* {{c_state_failed}} */
.step.failed   { background: #fce8e8; border-color: #e57373; }
/* {{c_state_compensating}} */
.step.compensating { background: #fff3e0; border-color: #ffa726; }
/* {{c_state_compensated}} */
.step.compensated  { background: #f3e5f5; border-color: #ab47bc; }
.status-bar { font-size: .95rem; font-weight: 600; min-height: 1.5em; margin-bottom: .5rem; }
.status-bar.ok  { color: #2e7d32; }
.status-bar.bad { color: #c62828; }
.status-bar.warn { color: #e65100; }
.btns { display: flex; gap: .5rem; flex-wrap: wrap; }
button { font: 600 14px system-ui, sans-serif; padding: .45rem .9rem; border-radius: 8px;
         cursor: pointer; border: 1.5px solid #1d3557; background: #1d3557; color: #fff; }
button.danger { background: #c62828; border-color: #c62828; }
button.ghost  { background: #fff; color: #1d3557; }
button:disabled { opacity: .45; cursor: default; }
// Code not found

Notice that compensation is not rollback. A compensating transaction is a new forward action that logically reverses the effect of an earlier one — for example, issuing a refund rather than reversing a database write. Each step must be designed to be compensable from the start.

The Real Complexity

Sagas look simple: commit forward, compensate backward. The real difficulty lives in the corners.

  • Compensation can fail. A saga step that charged a card can in principle be compensated by a refund — but what if the refund API is also down? Real implementations need retry logic and idempotency keys so compensations can be safely re-attempted without double-refunding.
  • Order matters. Steps that can be compensated are called compensable; steps that cannot (because their effect is already visible to the outside world, like sending an email) are called pivot steps. A correct saga places all compensable steps before the pivot step. Once you cross the pivot, there is no clean undo.
  • Isolation is gone. Classical ACID gives you isolation: other transactions don't see your intermediate state. A saga has no such guarantee — another saga can read a half-committed state. This opens the door to anomalies like the lost update or the dirty read. Saga designers must reason about which anomalies their business logic can tolerate.
  • Two styles. A choreography saga has each service emit events that trigger the next service — simple to build, hard to trace when something goes wrong. An orchestration saga uses a central coordinator (a saga orchestrator) that issues commands and records the saga's state — easier to monitor and debug, at the cost of a new central component.

The pattern was described as solved by Garcia-Molina and Salem in 1987, but the engineering trade-offs — idempotency, pivot placement, anomaly tolerance — are decided fresh for every workflow. Unlike a simple scheduling problem where optimal is well-defined, a correct saga design depends on what your business can actually tolerate.

Where It Matters

Any workflow that must stay consistent while touching more than one service lives in saga territory:

  • E-commerce checkout: reserve stock, charge payment, create shipment, send confirmation — four services, four local commits, and a compensation chain ready to fire if any step fails.
  • Airline booking: hold a seat, process payment, issue a ticket, update frequent-flyer miles — each managed by a separate legacy system that cannot share a database transaction.
  • Bank transfers: debit the source account, credit the destination, notify both customers — the compensation for a failed credit is a reversal debit on the source.
  • Healthcare scheduling: book an appointment slot, verify insurance, notify the provider, send a patient reminder — a failed insurance check must release the slot and suppress the notifications.
  • Microservice orchestration frameworks: AWS Step Functions, Netflix Conductor, Temporal, and Axon Framework all implement saga-style orchestration under the hood.

Wherever you see a multi-step workflow with "undo" requirements, you are looking at a saga. The pattern is the distributed-systems answer to the same question that load balancing asks at the infrastructure level: how do you keep a system consistent and available when no single node controls everything?

Conclusion

The saga pattern is a reminder that consistency is negotiable. Classical transactions give you all-or-nothing atomicity, but they demand a shared lock — a luxury distributed systems cannot always afford. Sagas trade that luxury for availability, breaking the workflow into steps that each commit fast and each know how to undo themselves.

That trade is never free. Compensations must be designed, idempotency must be enforced, and pivot steps must be placed carefully. But the reward is a system that stays available under partial failures — and that, at scale, is usually worth every extra line of compensation logic.

The next time you get a refund e-mail after a booking fails, you've seen a saga run its compensation chain to completion. Behind the scenes, each service ran its undo step in reverse order, leaving the world exactly as it was before you clicked "Book." Not magic — just a 1987 paper made software.

Share this article

Pick a channel — or use your device's native share sheet.

Comments

Loading comments...

https://www.kipuhub.com/en/article/saga-pattern/Content licensed under CC BY-NC 4.0.