Lesson 16 / 25

Consistency Without Distributed Transactions

Keep data consistent across services with sagas, outbox and idempotency.

Giving up the single transaction

In a monolith, placing an order, reserving stock and recording payment can be one ACID transaction. Across services with separate databases, that is gone. Two-phase commit across services is rarely used in practice: it couples availability and is poorly supported by modern datastores and brokers. Instead, use a saga: a sequence of local transactions, each in one service, with compensating actions to undo earlier steps on failure (release stock, refund payment). Sagas can be choreographed through events or orchestrated by a coordinator or workflow engine. Publish events reliably with the transactional outbox, and make consumers idempotent, because messages can arrive more than once. Design the user experience for eventual consistency: "Order received" first, then "Order confirmed". The Event-Driven Architecture course covers these patterns in depth.

A saga instead of one transaction

Local transactions run step by step; a failure triggers compensations in reverse.

A row of three step boxes connected by forward arrows, with a dashed set of backward arrows underneath representing compensations.
Figure 6.1 — Forward steps and compensating actions in a saga.

Steps and compensations for checkout

Each forward step has a defined undo; compensations must be idempotent.

step                         service      compensation
---------------------------  -----------  ---------------------------
1 create order (PENDING)     orders       mark order CANCELLED
2 reserve stock              inventory    release reservation
3 authorise payment          payments     void authorisation / refund
4 confirm order              orders       (last step, nothing after it)

failure at step 3 -> run compensations for 2, then 1
all steps and compensations: idempotent, keyed by orderId

Compensations are business decisions

"Undo" is not always possible: an email cannot be unsent and a parcel may already be shipped. Agree with the business what compensation means for each step, such as a follow-up email or a return label.

Quick check: What replaces a cross-service ACID transaction in most microservice systems?

  • A shared database lock
  • Two-phase commit across every service
  • A saga of local transactions with compensating actions
  • Running all services in one process
Answer

A saga of local transactions with compensating actions — Sagas keep each step local and undo completed steps with compensations on failure.