Topic 15.2
Sagas: Distributed Workflows with Compensation
In one line
A saga replaces a distributed transaction with a sequence of local transactions, each publishing an event; if a later step fails, compensating actions undo earlier ones (refund payment, cancel order). Implement with choreography or an orchestrator, and design for idempotency, timeouts and partial failures.
Think of it like this
Booking a holiday. You book the flight, then the hotel, then the car. If the car can't be booked, you don't "roll back time"; you cancel the hotel and the flight (compensations), possibly with fees.
Key ideas
- 01
Why sagas: each service has its own database; no two-phase commit across them (and Kafka can't join a DB transaction). Consistency becomes eventual, driven by events.
- 02
Steps and compensations: Order created → Payment authorized (compensation: void/refund) → Inventory reserved (compensation: release) → Shipment created (compensation: cancel shipment). Compensations must be idempotent and commutative with retries.
- 03
Orchestrated saga: an orchestrator stores saga state (a table or a workflow engine), sends commands (
ReserveInventory), waits for replies, handles timeouts ("no reply in 30 s → retry or compensate"), and triggers compensations in reverse order. - 04
Choreographed saga: services listen for failure events and compensate themselves (
InventoryRejected→ payment service refunds). Works for short flows; gets tangled for long ones. - 05
Semantic concerns: intermediate states are visible ("payment taken, stock not yet reserved"); design UX and invariants for them, and use pivot steps (after which the saga only moves forward) carefully.
Code & diagrams
CREATE TABLE order_saga (
order_id text PRIMARY KEY,
state text NOT NULL, -- STARTED, PAID, RESERVED, SHIPPED, COMPENSATING, CANCELLED, DONE
step_started timestamptz NOT NULL,
attempts int NOT NULL DEFAULT 0,
version int NOT NULL DEFAULT 0 -- optimistic locking for concurrent events
);
-- A timeout job: sagas stuck in PAID for > 5 minutes -> resend ReserveInventory or compensate.Interview problem
The problem
E-commerce saga: order, payment, inventory, shipping, notification
Design the order workflow with Kafka: Order, Payment, Inventory, Shipping and Notification. Discuss idempotency, ordering, retries, compensation, failures, timeouts and DLTs.
The interviewer follows up
Why not use Kafka transactions for the whole order flow?
Explain it without notes
Why must compensations be idempotent?
Practice
Implement a two-step saga (payment then inventory) with a failing inventory step and verify the refund happens exactly once.
Trade-offs
- ↔
Sagas give cross-service consistency without distributed locks, at the cost of visible intermediate states and compensation logic.
Done when you can
I can design orchestrated and choreographed sagas with idempotent steps, compensations and timeouts.