advanced~2.5h

The Saga Pattern

If 2PC doesn't survive real production microservices, what actually does? This module is the pattern nearly every real distributed system uses instead.

Learning objectives

  • Beginner: Explain what a compensating transaction is and why Sagas need them.
  • Intermediate: Trace through a multi-step Saga's happy path and its failure/rollback path.
  • Advanced: Choose between choreography-based and orchestration-based Saga implementation for a given system's complexity.

◆ The problem

2PC tried to make multiple services' writes atomic TOGETHER. A Saga gives up on that entirely, and instead breaks a business operation into a SEQUENCE of independent local transactions — each one fully committing on its own — with an explicit COMPENSATING transaction defined for each step, to undo it if a LATER step in the sequence fails.

Placing an order becomes: (1) create the order [local tx], (2) reserve inventory [local tx], (3) charge payment [local tx] — if step 3 fails, the Saga runs a compensating action for step 2 (release the inventory reservation) and step 1 (cancel the order), rather than trying to roll back a single distributed transaction that never existed in the first place.

ChoreographyOrchestration
Who decides the next step?Each service reacts to events and decides its own next actionOne central orchestrator explicitly tells each service what to do
CouplingLoose — services only know about events, not each otherThe orchestrator knows about every participating service
Complexity as steps growGets hard to trace ("who reacts to what")Stays centrally visible, but the orchestrator becomes a critical component

Choreography fits naturally with the Kafka & Microservices category's event-driven architecture — each service publishes an event (OrderCreated) and reacts to events from others (InventoryReserved), with no service directly calling another. In actual Spring code, that's just an ordinary @KafkaListener on each participant:

// inventory-service @KafkaListener(topics = "order-events") public void onOrderCreated(OrderCreatedEvent event) { boolean reserved = inventoryService.tryReserve(event.orderId(), event.items()); kafkaTemplate.send("inventory-events", reserved ? new InventoryReservedEvent(event.orderId()) : new InventoryReservationFailedEvent(event.orderId())); } // order-service — reacts to the compensating case @KafkaListener(topics = "inventory-events") public void onInventoryReservationFailed(InventoryReservationFailedEvent event) { orderService.cancel(event.orderId()); // the compensating transaction for step 1 }

No service calls another directly, and no central coordinator exists — each service only knows the shape of the events it listens for and publishes, which is exactly what "loose coupling" means concretely in code.

▲ Pitfall

A compensating transaction ISN'T simply the reverse of the original operation — "cancel the order" and "release the inventory reservation" are their own explicit business operations, each with their own edge cases (what if the reservation was already consumed by the time you try to release it?). Teams that design the happy path first and bolt compensating logic on afterward routinely discover these edge cases in production, not in design review.

A Saga's steps commit one at a time, not all at once — for a brief window between step 1 and step 3, the system is in an intermediate, temporarily-inconsistent state (the order exists, but payment hasn't been confirmed yet). This is the exact eventual-consistency trade-off the Databases Mastery — NoSQL category covers in depth: a Saga is that same trade-off, applied at the level of an entire business process instead of a single database write.

✓ Quick recap

  • A Saga replaces one distributed transaction with a sequence of independent local transactions, each with its own compensating action if a later step fails.
  • Choreography (event-reactive, no central coordinator) fits naturally with Kafka's event-driven style; orchestration (one central coordinator) stays more traceable as steps grow.
  • Compensating transactions are their own real business logic with their own edge cases — never assume they're just "the reverse operation."
  • A Saga is inherently eventually consistent, not atomic — the same trade-off covered for NoSQL databases, applied at the business-process level.

Want a visual for this concept?

Generate a diagram tailored to “The Saga Pattern” — the AI picks whichever visual (flowchart, comparison, sequence, etc.) best fits.

Sign in to generate a visual →

Practice quiz

Next Step

Continue to CQRS (Command Query Responsibility Segregation)← Back to all Spring Cloud chapters