Saga Pattern
Manage distributed transactions (Orchestration vs Choreography)
- Technology
- 4 min read
Introduction
In monolithic applications, managing transactions across multiple operations is straightforward because everything runs within a single database transaction. But in microservices, each service owns its own data, and a single business process often spans multiple services.
The Saga Pattern provides a way to manage distributed transactions without requiring a global lock or two-phase commit (which are slow and brittle). Instead, it breaks the transaction into a series of local transactions in different services, coordinated by events or a central orchestrator. If something fails, compensating actions are triggered to undo the completed steps.
Think of it as a relay race—each service runs its part and passes the baton. If a runner drops the baton, the team retraces steps to restore balance.
Problem Statement
- Business processes often span multiple services.
- Example:
Order Service→Payment Service→Inventory Service→Shipping Service. - Failures in the middle may leave the system in an inconsistent state (e.g., money deducted but no item shipped).
- Traditional distributed transactions (2PC) are too slow and complex.
- We need a way to ensure data consistency without central locking.
Concept Overview
Definition:
A Saga is a sequence of local transactions. Each local transaction updates data within one service and publishes an event or triggers the next step.
If one step fails, the saga executes compensating transactions to undo the previous steps.
Two Coordination Styles:
- Choreography (Event-based) → each service listens for events and reacts.
- Orchestration (Central controller) → a saga orchestrator tells each service what to do.
Flow Example (Order Processing):
Order Service → Payment Service → Inventory Service → Shipping Service ^ | | | | v v v Compensation Refund Payment Restock Item Cancel Shipment
When to Use
- Business processes that span multiple microservices.
- Where eventual consistency is acceptable.
- When you want to avoid distributed locks or 2PC.
- E-commerce, banking, bookings, supply chain workflows.
When to Avoid
- Systems that require strict immediate consistency.
- Very simple workflows (Saga may be overkill).
- Workflows with no safe compensating actions.
- Extremely complex workflows → orchestration may get bloated.
Architecture / Flow
1. Choreography Saga (Event-driven)
- Each service listens for events from the previous one.
- Decentralized, no single point of control.
- Risk of event chaos if not managed well.
2. Orchestration Saga
- A central orchestrator controls the flow.
- More structured, easier to monitor.
- Orchestrator may become a single point of failure.
Implementation (Step-by-Step)
Example: Order Processing Saga (Orchestration)
- Order Service → creates an order (pending).
- Orchestrator → tells Payment Service to process payment.
- If payment succeeds → orchestrator tells Inventory Service to reserve items.
- If inventory succeeds → orchestrator tells Shipping Service to ship the product.
- If any step fails → orchestrator triggers compensation steps (e.g., refund payment, cancel order).
Example Snippet (Pseudocode - Orchestration Style)
class OrderSagaOrchestrator: def start_order(self, order_id): try:
self.call_payment(order_id)
self.call_inventory(order_id)
self.call_shipping(order_id) print("Order completed successfully.") except Exception as e: print("Error detected, compensating...")
self.compensate(order_id) def call_payment(self, order_id): # simulate call print("Payment successful for order:", order_id) def call_inventory(self, order_id): raise Exception("Inventory unavailable!") # simulate failure def call_shipping(self, order_id): print("Shipping initiated for order:", order_id) def compensate(self, order_id): print("Refund payment, cancel order, release resources.")
Advantages
- Enables distributed transactions without global locks.
- Ensures data consistency across services.
- Works with eventual consistency models.
- Supports compensation logic for graceful rollback.
- Scales well with event-driven systems.
Disadvantages / Pitfalls
- Adds complexity to design and testing.
- Compensation logic may be hard to define.
- Risk of cascading rollbacks across services.
- Orchestration → risk of central bottleneck.
- Choreography → risk of spaghetti event flows.
Best Practices
- Use idempotent operations (safe to retry).
- Ensure compensating transactions are reliable.
- Keep events simple and clear (avoid chaos in choreography).
- Monitor saga execution with tracing and logs.
- Choose orchestration for complex workflows, choreography for simple ones.
Common Mistakes to Avoid
- Not defining compensation logic → leads to inconsistencies.
- Overloading orchestration logic → monolithic orchestrator.
- Under-documenting event flows in choreography.
- Ignoring timeouts and retries in saga steps.
Comparison with Alternatives
- 2PC (Two-Phase Commit): Strong consistency but not scalable, high latency.
- Orchestration vs. Choreography: Orchestration is centralized (easy to monitor, harder to scale), Choreography is decentralized (scalable but messy).
- Eventual Consistency vs. Immediate Consistency: Saga works with eventual consistency, not for cases requiring strong ACID compliance.
Real-World Use Cases
- E-commerce: Order → Payment → Inventory → Shipping.
- Banking: Transfer money between accounts across services.
- Travel Booking: Reserve flight, hotel, and car rental. If one fails, cancel all.
- Telecom: Activating a new service plan across billing, provisioning, and network systems.
Expert Tips 🔥
- Use state machines (e.g., AWS Step Functions, Temporal.io) to model orchestrations.
- For choreography, use an event bus like Kafka to manage events.
- Test compensation flows as carefully as success flows.
- Introduce dead-letter queues for failed events.
- Consider hybrid approaches: Orchestration for core flow, choreography for side events.
Conclusion / Key Takeaways
The Saga Pattern is the backbone of handling distributed transactions in microservices. By breaking down workflows into smaller local transactions with compensation, it enables systems to maintain consistency without central locking.
It’s a powerful resilience tool that balances complexity with reliability, making it a must-know for anyone designing enterprise-scale microservices.
💡 In short: Saga ensures your microservices don’t break under the weight of distributed transactions—they dance in a coordinated sequence, recovering gracefully when one step misfires.