Software Architecture/Engineering  

Microservices Pattern: Distributed Transactions Using SAGA

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:

  • C3 → C2 → C1

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

  1. Order Service creates an order with status PENDING

  2. Inventory Service reserves stock

  3. Payment Service charges the customer

  4. Order Service updates the order status to CONFIRMED

Failure Scenario

  1. Payment fails

  2. Inventory Service releases reserved stock

  3. Order Service cancels the order

Two Ways to Implement SAGA

1. Choreography (Event-Based SAGA)

In choreography:

  • There is no central coordinator

  • Each service reacts to events and publishes new events

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

  • Simple for small workflows

  • Loosely coupled services

  • No central service required

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

  • Clear and easy-to-follow workflow

  • Easier debugging

  • No cyclic event dependencies

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:

  • OrderId

  • TransactionId

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:

  • Inventory should not reserve stock twice

  • Payment should not charge twice

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:

  • Choreography (event-based)

  • Orchestration (central controller)

Both approaches are widely used in real-world systems, and the choice depends on system complexity and operational needs.