DBRaven
Pattern · consistency

Saga Pattern

mature

Summary

Run a business transaction that spans multiple services as a sequence of local transactions, each atomic in its own service and each paired with a compensating transaction that semantically reverses it if a later step fails. It trades isolation for service autonomy: concurrent sagas can observe each other's intermediate state.

Problem

Business operations that span multiple microservices (reserve inventory, charge payment, create shipment) cannot be wrapped in one ACID transaction. Without coordination, a partial failure leaves the system inconsistent with no defined recovery path.

Description

A transaction spanning multiple services cannot be wrapped in one ACID transaction without 2PC, which is blocking and impractical across heterogeneous, independently owned services. A saga instead models the work as a sequence of local transactions T1, T2, ... Tn, each atomic within its own service. If step Tk fails, the saga runs compensating transactions C(k-1), C(k-2), ... C1 in reverse to undo the steps that already committed.

A saga gives ACD, not ACID. It provides atomicity in the sense that the sequence eventually either fully completes or is fully compensated, consistency, and durability, but it gives up isolation. That missing I is the whole design tension. Because each Ti commits on its own, there is no boundary hiding the half-finished saga from anyone else.

Lack of isolation and observable intermediate states. While a saga is mid-flight, its committed-but-not-yet-final steps are visible to concurrent transactions. Another saga can read state left by T1 before Tn runs or before compensation reverses it, which produces business-level anomalies: a dirty read of state that will be compensated away, or a lost update when two sagas touch the same record. The database will not prevent this, so the application must.

Countermeasures live in the application, not the engine. The common one is a semantic lock: a saga marks the records it is working on with an in-progress or pending flag, and other transactions treat a flagged record specially (wait, reject, or handle it as tentative) rather than acting on half-done state. Others include commutative updates, designing steps so their order does not change the result (increment and decrement rather than set), and reread-or-version checks that detect a concurrent modification before committing. These reintroduce, by hand, the isolation the saga gave up.

Choreography failure modes. In a choreographed saga each service publishes an event on completion and subscribes to others' events to know when to act; there is no coordinator, and the transaction emerges from the event flow. It is simple to deploy but the saga's state is implicit, scattered across topics, so understanding or debugging a stuck saga means correlating events across services, and cyclic event dependencies appear beyond a few steps. It suits sagas of 2 to 4 steps.

Orchestration failure modes. In an orchestrated saga a central orchestrator, usually a state machine persisted in PostgreSQL, commands each participant and issues compensations on failure. It gives one place to observe and audit saga state, which suits 5-plus steps and complex error handling, but the orchestrator is a single point of failure and potential bottleneck: it must persist its state durably and deliver commands at-least-once so a restart resumes in-flight sagas rather than losing them.

Compensation is not rollback. A committed step really happened and may have had external side effects (an email sent, a card charged). Compensation does not erase it; it issues a new forward transaction that semantically reverses it (a refund, not an un-charge). That compensation can itself fail, which needs a dead-letter path and manual intervention, and some effects cannot be reversed at all. Because delivery is at-least-once, every step and every compensation must be idempotent, or a redelivery will double-charge or double-allocate.

Tradeoffs

Distributed consistency
+0.7

Provides a structured recovery path for multi-service transactions

Service autonomy
+0.8

Each service owns its local transaction; no cross-service locking

Isolation
-0.7

No isolation between concurrent sagas; intermediate state is observable unless the app adds countermeasures

Debugging complexity
-0.6

Choreography requires event correlation; orchestration adds a stateful coordinator

Compensation reliability
-0.5

Compensation failures are a second-order failure mode requiring explicit handling

Observability
-0.3

Orchestration gives a single audit trail; choreography requires correlation

When to use

A business transaction spans multiple services or data stores

2PC across services is blocking and impractical; Saga provides a structured eventual-consistency model with defined compensation.

Services are independently deployable and owned by different teams

Synchronous cross-service coupling (2PC, distributed locks) couples availability and deployment; Saga decouples via events or async commands.

A compensating transaction can be defined for every forward step

Saga is only viable if each step has a defined compensation; non-compensable steps (a physical shipment) need a different approach, such as ordering them last.

Eventual consistency at the business-transaction level is acceptable

Saga provides no isolation between concurrent sagas; intermediate state is observable unless the application adds semantic locks or similar countermeasures.

When not to use

Steps cannot be compensated (e.g., external side effects that cannot be reversed)

If a step cannot be reliably reversed, Saga cannot restore consistency; hold that step until all others are certain, or choose another approach.

Strong isolation between concurrent transactions is required

Saga provides no isolation; concurrent sagas can read each other's intermediate state. Serializable isolation within one database, or 2PC, is needed instead.

The transaction spans only a single service and database

A local ACID transaction is simpler, faster, and strictly stronger.

Operational Requirements

mandatory

Define and implement a compensating transaction for every forward step before deployment

Compensation cannot be added retroactively; a missing compensation means permanent inconsistency when its step fails.

mandatory

Make every step and every compensation idempotent

At-least-once delivery means steps run more than once; non-idempotent steps double-charge, double-allocate, or create duplicates.

recommended

Apply an isolation countermeasure (semantic lock or equivalent) for records touched mid-saga

Without a semantic lock or commutative design, concurrent sagas read each other's intermediate state; flag in-progress records so others handle them as tentative.

mandatory

Instrument saga state transitions and dead-letter compensation failures

A saga stuck in COMPENSATING is inconsistent business state; compensation failures must alert immediately for manual resolution.

mandatory

Persist orchestrator state durably (PostgreSQL) with at-least-once command delivery

An orchestrator restart must resume in-flight sagas; in-memory state loses every in-progress transaction on restart.

Characteristics

Scales on
Implementation complexityhigh
Operational complexityhigh
Scaling ceilingChoreographed sagas become undebuggable beyond 5 to 6 steps without dedicated saga-tracking infrastructure, as state is spread across topics. Orchestrated sagas concentrate the risk in the orchestrator, which is a bottleneck and single point of failure unless deployed with HA and durable state. Compensation failures (a compensating transaction that itself fails) are a distinct class of failure that needs a dead-letter path and manual resolution designed in from the start.

Technologies

Canonical

kafkapostgresqlrabbitmq

Alternatives

temporal ioaws step functionsaxon frameworkconductor

Relationships

Evolves from

two phase commit

Complements

event sourcingoutbox patterncircuit breakerdatabase per service

Conflicts with

two phase commit

Basis

Well-established pattern in microservice architectures; the isolation gap and its application-level countermeasures, and compensation failure as a second-order risk, are documented in the saga literature and in production incident reports.

Related Architecture Knowledge

Outbound: this entity affects

MitigatesPattern
two phase commit
Grounded

Saga replaces two-phase commit with a sequence of local transactions and compensating transactions, eliminating the blocking distributed lock problem of 2PC at the cost of eventual consistency and more complex failure handling.

Tradeoffs

  • ·Saga does not provide atomicity: intermediate states are visible between steps
  • ·Compensating transactions add implementation complexity: every step needs a corresponding undo operation
  • ·{'Eventual consistency': 'a saga rollback takes time: the system is briefly inconsistent during compensation'}
Full relationship →

Inbound: affects this entity

SupportsTechnology
temporal
Grounded

Temporal provides durable workflow execution with compensation support, implementing the saga pattern without custom state machine code in the application.

Full relationship →

Used In Architecture Scenarios

E-Commerce Order Platformhigh

Marketplace Platform

An e-commerce order lifecycle platform handling cart, checkout, payment, fulfillment, and returns across a mixed read/write workload where product discovery is read-heavy, checkout is write-transactional, and fulfillment is event-driven. The saga pattern orchestrates multi-step checkout: reserve inventory → charge payment → confirm order → notify fulfillment. PostgreSQL owns order records and inventory with row-level locking; Redis holds session state and cart contents with sub-millisecond access; RabbitMQ delivers fulfillment notifications with dead-letter handling; Elasticsearch serves product search and order history with faceted navigation. CQRS separates the write command path from the read model: the order read model is denormalized for fast order history queries without joining across domain tables.

Two-Sided Marketplace Platformexpert

Marketplace Platform

A two-sided marketplace architecture serving buyers, sellers, listings, transactions, search, and notifications from a shared infrastructure, where multiple independent domains must coordinate without tight coupling. Event sourcing captures every state transition; the saga pattern orchestrates multi-step transactions (create order, reserve inventory, charge payment, notify seller) with compensating transactions for partial failures. Kafka decouples domain event publication from consumption; RabbitMQ handles notification fanout; Elasticsearch serves listing search; Redis caches listing display and session state.

Saga Pattern: DBRaven