SAGA Pattern in Microservices with E-commerce Example

    SAGA Pattern in Microservices with E-commerce Example

    Learn the Saga Pattern in Microservices with a Real-World E-commerce Example. Understand how to handle distributed transactions using choreography and orchestration, the pros and cons of 2PC, 3PC, and why Saga is the better solution for data consistency in microservices.

    default profile

    Santosh Mane

    May 13, 2025

    6 min read

    If you've worked with microservices, chances are you've stumbled upon the term "Saga Pattern" at some point. Maybe in a Slack conversation, a tweet from a senior engineer, or that one architectural meeting where everyone was nodding (but only half of us actually knew what was going on 😅).

    So today, I’m going to walk you through this magical concept — not in a robotic, textbook-y way — but like a friend helping you figure this out over a cup of coffee (virtual or real ☕).

    Let’s do this! 🚀

    Introduction#

    Let’s imagine you're shopping on your favorite e-commerce app 🛍️. You:

    1. Place an order for a brand-new pair of shoes 👟
    2. Make the payment 💳
    3. The system processes shipment 📦

    Now, let’s say everything goes smoothly — fantastic. But wait... what if your payment fails due to a banking glitch? Uh-oh.

    In a monolithic app, you'd just roll back the entire transaction since it's all in one place — one database, one transaction scope. Easy-peasy.

    But in a microservices setup:

    • The Order Service creates the order.
    • The Payment Service handles the transaction.
    • The Shipment Service prepares to ship the product.

    Each of these has its own database. They don’t know what’s going on in the others.

    So if payment fails, your order is still marked as placed unless someone tells the Order Service to cancel it. That’s bad UX. Even worse — it leads to data inconsistency.

    🎉 And this is where the SAGA Pattern swoops in like a superhero 🦸.

    The Problem: Distributed Transactions#

    In a monolith, you’ve probably used transactions like:

    BEGIN TRANSACTION; -- Do some stuff -- Commit if everything's fine, or rollback if not

    All good. Everything is ACID compliant (Atomic, Consistent, Isolated, Durable).

    But in distributed systems, there’s no shared database. Transactions are local to each microservice. So, if one operation fails, we have to manually undo everything else — and that gets messy fast.

    That’s where distributed transaction patterns like 2PC, 3PC, and SAGA come into play.

    Two-Phase Commit (2PC)#

    How it works:

    1. Phase 1: Prepare – Each service says, "I’m ready to commit."
    2. Phase 2: Commit – If all say yes, the coordinator says, "Commit it all."

    Example:#

    Let’s say you’re placing that e-commerce order.

    • Order Service: Ready
    • Payment Service: Ready
    • Shipment Service: Ready

    Cool. Everyone commits.

    But… what if one of the services crashes after saying "ready" but before committing? 😬 Now you have inconsistent data.

    Drawbacks of 2PC:#

    • Blocking: Services wait on each other. Not good for performance.
    • Single point of failure: Coordinator goes down? Game over.
    • Not fault-tolerant: Crashes during commit phase = zombies 🧟

    Three-Phase Commit (3PC)#

    3PC adds a new phase called "Pre-Commit" to avoid those zombie states.

    Phases:

    1. Can you commit? (Like 2PC’s Prepare)
    2. Pre-commit (Everyone gets a heads-up to get ready)
    3. Commit

    Example:#

    Placing the same e-commerce order.

    • Phase 1: Everyone says "Yeah, I can commit."
    • Phase 2: "Okay, I’m preparing to commit."
    • Phase 3: "Do it now!"

    Sounds cool, right?

    Drawbacks:#

    • Still slow (3 phases now).
    • Still relies on a central coordinator.
    • Complex AF (especially when you factor in retries, network failures, etc.)

    So what do we do?

    Say hello to our friendly pattern: SAGA.

    Enter the Saga Pattern#

    Here’s the thing:

    Instead of wrapping everything in a big, scary transaction, Saga breaks it down into smaller local transactions.

    Each step is a local transaction. If one step fails, you trigger a compensating transaction to undo the previous steps.

    Kinda like:

    • Step 1: Create Order
    • Step 2: Make Payment
    • Step 3: Prepare for Shipment

    If payment fails, the Payment Service emits a PaymentFailedEvent, and the Order Service listens to it and cancels the order (updates the order status to cancelled).

    💡 Think of it like a chain of promises — each with a backup plan.

    Types of SAGA: Choreography and Orchestration#

    1. Choreography (Everyone Just Knows What to Do)#

    • No central controller.
    • Services publish events and listen to other services' events.

    E-commerce Example:#

    Choreography based Saga
    1. The Order Service creates an order and emits an OrderCreatedEvent.
    2. The Payment Service listens to the OrderCreatedEvent, processes the payment, and emits either:
    3. PaymentCompletedEvent (if successful), or
    4. PaymentFailedEvent (if failed).
    5. If payment is successful, the Shipment Service listens to the PaymentCompletedEvent, arranges the shipment, and emits a ShippingArrangedEvent.
    6. The Order Service listens to the ShippingArrangedEvent and updates the order status to CONFIRMED or SHIPPED.
    7. If the Payment Service emits a PaymentFailedEvent, the Order Service listens to it and updates the order status to CANCELLED.

    Pros:

    • No central brain.
    • Decentralized and loosely coupled.

    Cons:

    • Hard to track the flow.
    • Debugging is a pain.

    2. Orchestration (There’s a Conductor)#

    • One central Saga Orchestrator tells each service what to do.

    E-commerce Example:#

    Orchestration based Saga
    1. A user places an order.
    2. The Order Service creates the order and notifies the Saga Orchestrator.
    3. The Saga Orchestrator sends a command to the Payment Service to initiate the payment.
    4. If the payment is successful, the Payment Service emits a PaymentCompletedEvent.
    5. The Saga Orchestrator listens to this event and sends a command to the Shipping Service to initiate shipment.
    6. Once the shipment is completed, the Shipping Service emits an OrderShippedEvent.
    7. The Order Service listens to the OrderShippedEvent and updates the order status to SHIPPED or COMPLETED.

    If something fails along the way:

    1. For example, if the payment fails, the Payment Service emits a PaymentFailedEvent.
    2. The Saga Orchestrator, upon receiving this event, sends a command to the Order Service to cancel the order — this is called a compensating transaction.

    Pros:

    • Easier to visualize and monitor.
    • Centralized error handling.

    Cons:

    • Orchestrator can become a bottleneck.
    • Slightly more coupling.

    Real Talk: Saga Isn’t Always Easy#

    Let’s be real — implementing Sagas can be tricky. You have to:

    • Define clear compensation logic.
    • Handle partial failures.
    • Make sure your services are idempotent (retrying should not mess stuff up).
    • Maintain proper logging and tracing.

    But it’s way better than zombie data or blocking your microservices with 2PC!

    Key Takeaways#

    • Distributed transactions are tricky in microservices.
    • 2PC and 3PC try to solve this but come with serious trade-offs.
    • SAGA is a better alternative — breaking transactions into local steps.
    • You can implement SAGA via Choreography or Orchestration.

    Bonus Tips:#

    • Use Kafka or RabbitMQ for event-driven choreography.
    • For orchestration, frameworks like Axon, Camunda, or even Netflix Conductor help a lot.
    • Always make compensation actions safe and idempotent.

    Conclusion#

    So, that’s the lowdown on the Saga Pattern. It's like having a backup plan at every step — and let’s face it, we all need a good backup plan in distributed systems (and life 😅). Next time you build a flow with multiple microservices, ask yourself: “What happens if this step fails?” If the answer is “Uh… I dunno,” then maybe it’s time to bring in a Saga. Stay curious, and happy coding!

    Low Level Design
    SAGA Pattern
    Distributed Transactions
    Microservices Architecture

    More articles