Introduction
In a microservices architecture, each service usually owns its own database. This approach improves scalability and loose coupling, but it introduces a major challenge:
How do we keep data consistent when a single business operation updates multiple services?
In a monolithic application, this problem is easy to solve using a single ACID database transaction. In microservices, however, a single transaction cannot span multiple databases.
This is where the SAGA pattern is used.
In this article, you will learn:
Why distributed transactions are difficult in microservices
Why two-phase commit (2PC) is not recommended
What the SAGA pattern is and how it works
Compensating transactions
Choreography vs orchestration
A real-world create order example
Key points to remember
From Monolithic to Microservices
Why Transactions Are Easy in Monolithic Applications
In a monolithic architecture, most operations run inside a single database transaction.
Example: CreateOrder()
Check customer
Validate order
Deduct stock
Process payment
Save order
All these steps run in the same database, allowing:
COMMIT on success
ROLLBACK on failure
This approach is simple and reliable.
Why Distributed Transactions Are Hard in Microservices
In microservices, the same business operation is spread across multiple services.
Example: Create Order workflow
Order Service (Order DB)
Customer Service (Customer DB)
Inventory Service (Inventory DB)
Payment Service (Payment DB)
Each service owns its data, and the data is distributed.
The challenge becomes maintaining consistency when each service commits independently.
Why Not Use Distributed Transactions (2PC / XA)
A traditional solution is the two-phase commit (2PC) protocol.
In theory, it works as follows:
All services prepare to commit
All services commit together
If one fails, all roll back
In real microservices systems, this approach causes serious problems.
1. Technology Limitations
Many modern platforms and tools do not fully support XA transactions, including:
Kafka
RabbitMQ
Many NoSQL databases
2. Availability Issues
If a transaction spans four services, all four must be available at the same time. This significantly reduces system availability.
3. Performance and Locking
Distributed transactions lock resources for extended periods, leading to poor performance and reduced scalability.
For these reasons, 2PC is generally avoided in modern microservices.
What Is the SAGA Pattern?
The SAGA pattern is a microservices design pattern used to maintain data consistency without relying on distributed transactions.
A SAGA breaks a long business transaction into a sequence of local transactions.
Each step:
Executes within a single microservice
Commits changes to its own database
Publishes an event or sends a command to trigger the next step
If any step fails, compensating transactions are executed to undo previously completed steps.
Compensating Transactions
Because each local transaction commits immediately, SAGA cannot roll back automatically like ACID transactions.
Instead, it uses compensating transactions.
If:
T1 = transaction in Service 1
T2 = transaction in Service 2
T3 = transaction in Service 3
T4 = transaction in Service 4
And T4 fails, the system executes:
Example:
If payment fails, inventory is released and the order is canceled.
Example SAGA: Create Order
Services Involved
Order Service
Inventory Service
Payment Service
Happy Path
Order Service creates an order with status PENDING
Inventory Service reserves stock
Payment Service charges the customer
Order Service updates the order status to CONFIRMED
Failure Scenario
Payment fails
Inventory Service releases reserved stock
Order Service cancels the order
Two Ways to Implement SAGA
1. Choreography (Event-Based SAGA)
In choreography:
Example flow:
Order Service publishes OrderCreated
Inventory Service reserves stock and publishes StockReserved
Payment Service charges the customer and publishes PaymentCompleted
Order Service confirms the order
Benefits
Drawbacks
Hard to understand as workflows grow
Debugging becomes difficult
Event dependencies can become complex
2. Orchestration (Central Orchestrator SAGA)
In orchestration:
A central orchestrator controls the workflow
The orchestrator sends commands to services
Services respond with success or failure
Benefits
Drawbacks
Orchestrator can grow too large if poorly designed
Risk of creating a "smart orchestrator, dumb services" anti-pattern
Eventual Consistency
SAGA provides eventual consistency. Data may be temporarily inconsistent, but it becomes consistent once all steps or compensations complete. This behavior is expected and acceptable in microservices.
Best Practices for SAGA in Real Projects
1. Use Pending States
Examples:
PENDING
APPROVAL_PENDING
PAYMENT_PENDING
This prevents other processes from acting on incomplete data.
2. Use Correlation IDs
Every message or event should include:
This allows tracking of the entire workflow.
3. Use Reliable Messaging
SAGA implementations typically rely on message brokers such as:
RabbitMQ
Kafka
Azure Service Bus
4. Implement Idempotency
Services must handle duplicate messages safely.
Examples:
Conclusion
Distributed transactions are one of the hardest problems in microservices. Traditional 2PC/XA transactions reduce availability and restrict technology choices.
The SAGA pattern solves this by breaking a transaction into local transactions and using compensating actions to handle failures.
SAGA can be implemented using:
Both approaches are widely used in real-world systems, and the choice depends on system complexity and operational needs.