Overview

The Saga pattern maintains data consistency across multiple microservices without using distributed transactions. It replaces a single distributed transaction with a sequence of local transactions coordinated through messaging.

Problem

In a microservices architecture, each service has its own private database. Business operations that span multiple services cannot rely on a single ACID transaction. The natural alternative — distributed transactions using 2PC (Two-Phase Commit) — introduces serious problems:

  • 2PC is a complex, slow protocol that degrades as the number of participants grows
  • It uses synchronous communication, which reduces availability
  • Modern messaging technologies like RabbitMQ and Apache Kafka do not support distributed transactions
  • It creates tight coupling between services

Solution

A saga is defined for each operation that needs to update multiple microservices (participants). It consists of a sequence of local transactions — each microservice executes its local transaction and publishes a message or event to trigger the next participant.

If a participant fails, the saga executes compensation transactions to undo the changes made by preceding services. These compensation transactions perform the inverse of what was executed — ensuring the system returns to a consistent state.

Coordination Approaches

There are two ways to coordinate the participants of a saga:

Choreography

Each participant decides the next step after completing its local transaction by publishing an event. Coordination is decentralized and event-driven — no central orchestrator is needed. Services react to domain events emitted by other services.

Orchestration

A dedicated orchestrator microservice coordinates the saga by sending command messages to each participant and receiving response messages. Coordination is centralized.

The orchestration approach has simpler unidirectional dependencies between the orchestrator and participants, avoiding dependency cycles and simplifying business logic. However, the orchestrator becomes a single point of failure.

Trade-offs

Benefits

  • Maintains consistency across services without distributed transactions
  • Works with messaging systems like Kafka and RabbitMQ
  • Loosely coupled — services only communicate via messages/events
  • Orchestration simplifies business logic in complex flows

Drawbacks

  • Lack of ACID isolation — intermediate states are visible to other operations
  • Complexity of designing and testing compensation transactions
  • Orchestrator becomes a single point of failure (orchestration approach)
  • Harder to debug than a single transaction

When to Use

Apply Saga when:

  • A business operation spans multiple microservices and requires consistency
  • You are using messaging infrastructure that doesn't support 2PC
  • You need to avoid the availability and scalability problems of distributed transactions
  • The flow is complex enough to benefit from centralized coordination (use orchestration)

Consider alternatives when:

  • The operation spans only a single service — use a local ACID transaction
  • Strong ACID isolation is a hard requirement — Saga only provides eventual consistency