Instead of relying on a single ACID transaction, a Saga divides a business transaction into a sequence of local transactions.
Each service updates its own database and then invokes the next step by publishing an event or calling another service.
If a later step fails, previously completed operations are reversed using compensating transactions rather than rolling back a single database transaction.
The Saga Pattern is widely used in Spring Boot microservices because each service owns its own database, making traditional distributed transactions such as Two-Phase Commit (2PC) impractical.
Why Do We Need the Saga Pattern?
Consider an e-commerce application where placing an order involves multiple microservices. Order Service
|
+-------+-------+-------+
| | |
v v v
Inventory Payment Shipping
Service Service Service
Suppose the following sequence occurs.
- The Order Service creates the order.
- The Inventory Service reserves the products.
- Payment processing fails.
At this point, the order has already been created and the inventory has already been reserved, leaving the system in an inconsistent state because the customer never completed the payment.
The Saga Pattern maintains consistency by executing compensating transactions for the previously completed steps.
Order Created
|
v
Inventory Reserved
|
v
Payment Failed
|
+------+------+
| |
v v
Release Inventory Cancel Order
Instead of rolling back a single database transaction, each service performs its own business-level compensation to restore a consistent state.
Saga Coordination Approaches
There are two common approaches for implementing the Saga Pattern.1. Choreography
In Choreography, services communicate using events. There is no central coordinator. Each service listens for events, performs its own local transaction, and publishes the next event in the workflow.
Order Service
|
Order Created Event
|
v
Inventory Service
|
Inventory Reserved Event
|
v
Payment Service
|
Payment Completed Event
|
v
Shipping Service
The Order Service publishes an event.
OrderCreatedEvent event =
new OrderCreatedEvent(order.getId());
kafkaTemplate.send("orders", event);
The Inventory Service consumes the event.
@KafkaListener(topics = "orders")
public void reserveInventory(
OrderCreatedEvent event
) {
inventoryService.reserve(event.getOrderId());
}
After successfully reserving inventory, the Inventory Service publishes an InventoryReservedEvent.
The Payment Service consumes that event, processes the payment, and publishes either a PaymentCompletedEvent or a PaymentFailedEvent.
Rollback is also handled through events. Suppose the payment gateway declines the payment after the inventory has already been reserved.
Instead of rolling back a distributed transaction, the Payment Service publishes a PaymentFailedEvent. Any interested service can react to this event by executing its own compensating transaction.
Order Created
|
v
Inventory Reserved
|
v
Payment Failed
|
+------+------+
| |
v v
Release Inventory Cancel Order
For example, the Inventory Service consumes the PaymentFailedEvent and releases the reserved inventory.
At the same time, the Order Service consumes the same event and marks the order as Cancelled. Each service is responsible only for undoing its own local transaction.
Choreography keeps services loosely coupled because they communicate only through events. Adding new consumers usually requires no changes to existing services, since producers are unaware of who consumes their events.
As the number of participating services grows, event flows become increasingly difficult to understand and debug.
Tracking an individual business transaction across many services, including all success and compensation events, can also become challenging.
2. Orchestration
In Orchestration, a central Saga Orchestrator coordinates the entire business transaction.Instead of communicating directly through events, each service receives commands from the orchestrator and returns its execution result.
The orchestrator decides which service to invoke next and, if a step fails, determines which compensating transactions must be executed.
Saga Orchestrator
|
+-------+-------+
| | |
v v v
Order Inventory Payment
Service Service Service
Suppose a customer places an order. The orchestrator first instructs the Order Service to create the order. After receiving a successful response, it instructs the Inventory Service to reserve inventory.
If inventory is successfully reserved, it then invokes the Payment Service to charge the customer.
If every step succeeds, the orchestrator completes the saga and may invoke additional services such as Shipping or Notification.
Create Order
|
v
Reserve Inventory
|
v
Process Payment
|
v
Create Shipment
|
v
Order Completed
Rollback is also coordinated by the orchestrator. Suppose the payment gateway declines the payment after the order has been created and inventory has been reserved.
Instead of relying on services to discover the failure through events, the orchestrator explicitly invokes the required compensating transactions.
Create Order
|
v
Reserve Inventory
|
v
Payment Failed
|
v
Release Inventory
|
v
Cancel Order
In this example, the orchestrator first calls the Inventory Service to release the reserved inventory. After inventory has been restored, it calls the Order Service to cancel the order.
Each service executes only its own local transaction, while the orchestrator manages the overall workflow and rollback sequence.
Orchestration provides a single place to define business workflows, making complex transactions easier to understand, monitor, and debug.
Since every step passes through the orchestrator, it has complete visibility into the current state of the saga. The trade-off is that the orchestrator becomes a central component in the architecture.
If business workflows change frequently, the orchestrator must be updated accordingly, and it can become more complex as additional services participate in the saga.
Saga with Apache Kafka
Spring Boot applications commonly implement the Choreography Saga Pattern using Apache Kafka.Each service publishes domain events to Kafka topics, while downstream services subscribe only to the events they are interested in. No service needs to know which other services consume its events.
Order Service
|
v
Kafka Topic
|
+------+------+------+
| | |
v v v
Inventory Payment Notification
Suppose a customer places an order. The Order Service saves the order in its local database and publishes an OrderCreatedEvent to the orders topic.
The Inventory Service consumes the event, reserves the required products, and publishes an InventoryReservedEvent.
The Payment Service then consumes that event, charges the customer, and publishes either a PaymentCompletedEvent or a PaymentFailedEvent.
Finally, the Shipping or Notification Service consumes the successful payment event and completes the remaining business operations.
If a step fails, compensation is also coordinated through Kafka events. For example, if payment fails after inventory has been reserved, the Payment Service publishes a PaymentFailedEvent.
The Inventory Service consumes this event and releases the reserved inventory, while the Order Service consumes the same event and marks the order as Cancelled.
Each service performs only its own compensating transaction, while Kafka distributes the events to all interested consumers.
Because Kafka stores events durably, consumers can recover from temporary outages and continue processing once they become available again. This improves reliability compared to direct synchronous service calls.
Kafka also supports multiple independent consumers for the same event.
For example, a single OrderCreatedEvent can be consumed simultaneously by the Inventory, Payment, Notification, Analytics, and Audit services without requiring any changes to the Order Service.
Its durable event storage, horizontal scalability, and asynchronous communication make Apache Kafka one of the most popular technologies for implementing event-driven Saga architectures in Spring Boot microservices.
Summary
The Saga Pattern enables distributed business transactions across multiple Spring Boot microservices without relying on distributed database transactions.Instead of a single global transaction, each service performs its own local transaction and, if necessary, executes a compensating transaction to undo previously completed work.
Spring Boot applications commonly implement Sagas using either Choreography with Apache Kafka or Orchestration with a dedicated coordinator.
Although this approach introduces eventual consistency and additional operational complexity, it provides a scalable and reliable solution for long-running distributed business workflows.