SYS ARCHITECTLearning Platform
Settings
Theory

The Saga Pattern: Distributed Transactions

📋 Overview

In a microservices architecture, a single business process often spans multiple services, each with its own database. Traditional ACID transactions (like 2PC) are avoided due to their blocking nature and poor scalability. The Saga Pattern solves this by breaking a large transaction into a sequence of Local Transactions. Each step updates its own database and triggers the next step. If a step fails, the Saga executes Compensating Transactions to undo the changes made by preceding steps, ensuring eventual consistency.


🏗️ Core Principles & Characteristics

  • Local Transactions: Each service performs its work and commits to its own database immediately.
  • Compensating Transactions: For every action (e.g., "Charge Card"), there must be an "Undo" action (e.g., "Refund Card").
  • Implementation Styles:
    • Choreography: Decentralized. Services exchange events without a central coordinator. Best for simple workflows.
    • Orchestration: Centralized. A "Saga Execution Coordinator" (SEC) tells each service what to do. Best for complex, multi-step business logic.
  • ACID vs. BASE: Sagas provide Atomicity and Durability but lack Isolation. They follow the BASE model (Basically Available, Soft state, Eventual consistency).

⚖️ Trade-offs: Pros & Cons

Pros

  • High Availability: Unlike 2-Phase Commit (2PC), Sagas are non-blocking. If one service is down, the entire system doesn't hang.
  • Scalability: Allows services to remain truly decoupled and geographically distributed.
  • Resilience: Built-in failure handling via compensation.

Cons

  • Complexity: Developers must write twice as much code (Action + Compensation).
  • Lack of Isolation: "Dirty Reads" are possible because local transactions commit before the entire Saga finishes.
  • Debugging: Tracing a distributed Saga across logs of 5 different services is significantly harder.

🌍 Real-World Implementation

  • Order-to-Cash Workflow:
    1. Order Service: Create Order (Status: PENDING).
    2. Payment Service: Charge Customer.
    3. Inventory Service: Reserve Stock.
    4. Order Service: Update Order (Status: CONFIRMED).
  • Compensating Example: If "Reserve Stock" fails, the Saga triggers "Refund Customer" in the Payment Service and "Cancel Order" in the Order Service.
  • Tools:
    • Temporal.io: A powerful workflow engine that handles Sagas, retries, and state management.
    • Camunda: BPMN-based orchestration.
    • Event Sourcing: Often used alongside Sagas to maintain a perfect audit trail of all state changes.

💡 Interview "Gotchas" & Tips

  • Gotcha: The Lost Update. Since Sagas lack isolation, two Sagas might update the same record simultaneously. Use Semantic Locking (e.g., setting a status to PENDING_UPDATE) to prevent this.
  • Gotcha: Failing Compensations. What if the "Refund" call itself fails? You must Retry the compensation indefinitely or move it to a Dead Letter Queue (DLQ) for manual intervention. Compensations must be idempotent.
  • Tip: If asked about 2PC vs. Saga, emphasize that 2PC is for Distributed Databases (low latency, high consistency) while Saga is for Microservices (high latency, eventual consistency).
  • Tip: Always mention the Transactional Outbox Pattern to ensure that the event triggering the next step is actually sent after the local DB commit.

📐 Suggested Architecture Primitives

  • Saga Orchestrator: A state machine to track the current step.
  • Message Broker: Kafka or RabbitMQ for reliable event delivery.
  • Transactional Outbox: To ensure atomicity between DB updates and event publishing.
  • Idempotency Keys: To prevent duplicate processing of events/compensations.
Canvas