The saga pattern is a way to keep a multi-step business transaction consistent across several services or systems without a single distributed lock. The transaction is split into a sequence of local transactions, each committed independently, and every step has a compensating action that semantically undoes it if a later step fails. In the reliability of automated workflows, sagas are the standard answer to the question of how to roll back work that spans systems which cannot share one database transaction.
The idea dates back to database research in the late 1980s, where long-lived transactions were broken into steps to avoid holding locks for hours. Today the pattern is central to microservices, workflow engines and integration platforms, where a booking, an order or an onboarding process touches payment, inventory, messaging and third-party APIs.
How the saga pattern works
A saga defines an ordered list of steps T1, T2 to Tn and a matching list of compensations C1, C2 to Cn. Each step commits its own change and then triggers the next. If step Tk fails, the saga runs the compensations for the already completed steps in reverse order, from Ck-1 back to C1. The result is not an exact restoration of the past state but a business-consistent outcome, such as a refunded payment instead of an erased one.
Sagas therefore provide eventual consistency rather than isolation. Between steps, other processes can observe intermediate states, for example a reserved seat that is not yet paid. Designers handle this with explicit statuses such as pending or reserved, and with semantic locks that mark a record as being in progress.
| Element | Role | Example in an order saga |
|---|---|---|
| Local transaction | Commits one step in one system | Reserve stock in the warehouse |
| Compensating action | Semantically reverses a step | Release the stock reservation |
| Pivot step | Point after which the saga must complete | Capture the payment |
| Retriable step | Must eventually succeed after the pivot | Send the confirmation email |
| Saga log or state | Records progress for recovery | Workflow history entry |
Orchestration and choreography
A saga can be coordinated in two ways. In orchestration, a central coordinator, often a workflow engine, calls each step, waits for the result and decides whether to continue or compensate. In choreography, each service listens for events and publishes its own, so the flow emerges from event subscriptions without a central controller.
| Aspect | Orchestration | Choreography |
|---|---|---|
| Control | Central coordinator | Distributed event handlers |
| Visibility | Whole flow in one place | Flow spread across services |
| Coupling | Services know the orchestrator | Services know event types |
| Best for | Long or complex flows | Short flows with few steps |
| Main risk | Coordinator as a bottleneck | Hidden cyclic dependencies |
For automation teams, orchestration is usually the safer default because the state of every running saga can be inspected, retried and audited from a single place. Choreography suits small, stable flows where adding a coordinator would be heavier than the problem.
Saga pattern compared with related reliability techniques
The saga pattern is often contrasted with two-phase commit, which locks all participants until a coordinator decides to commit or abort. Two-phase commit gives strong consistency but requires every participant to support the protocol and blocks resources during failures, which most SaaS APIs cannot offer. Sagas trade isolation for availability and loose coupling.
| Approach | Consistency | Locks held | Fits |
|---|---|---|---|
| Two-phase commit | Strong, atomic | Yes, across participants | Databases supporting the protocol |
| Saga pattern | Eventual, compensated | No global locks | Services and external APIs |
| Retry only | Eventual if retries succeed | No | Steps without business side effects |
| Manual reconciliation | Delayed, human-driven | No | Rare, low-volume exceptions |
Sagas rely on neighboring reliability practices. Idempotency lets a step or compensation run twice without double effects. A retry policy with exponential backoff handles transient faults before compensation is triggered. A dead letter queue captures compensations that themselves keep failing, so a person can intervene.
Designing compensating actions
Compensation is the hardest part of a saga. Some actions are easy to reverse, such as canceling a reservation; others are not reversible at all, such as sending an email or shipping a parcel. The common rule is to place irreversible steps after the pivot step, once success is practically certain, and to design them so they can be retried until they succeed.
- Make compensations idempotent, because they may be retried after timeouts.
- Compensate semantically: issue a refund or a correction record rather than deleting history.
- Persist saga state before calling each step, so recovery knows where to resume.
- Set timeouts for every step, since a missing reply is the most common failure.
- Alert on stuck sagas that remain in an intermediate state too long.
Pitfalls of the saga pattern
The most common mistake is assuming a saga behaves like a database transaction. Without isolation, dirty reads and lost updates can occur when two sagas touch the same record. Another pitfall is the ambiguous failure: a call times out, and the saga cannot tell whether the step committed. Querying the target system for status before compensating, or using idempotency keys, resolves most of these cases.
Teams also underestimate testing. Each failure point creates a different compensation path, so a saga with five steps needs tests for every possible failure position, including failures during compensation itself.
A non-technical view
Think of planning a trip. You book a flight, then a hotel, then a rental car. If the car is not available, you do not leave the flight and hotel in place. You cancel them one by one, in reverse order.
The saga pattern does the same for software. Each step is done separately. If something later fails, the earlier steps are undone with their own cancellation actions. The end result always makes business sense.
A concrete example
An online event platform sells tickets through an automated workflow with four steps: reserve seats, charge the card, issue tickets and send a confirmation. Each step calls a different service, and the payment provider is an external API.
The team implemented the flow as an orchestrated saga in a workflow engine. If the payment fails, the saga releases the seats. Card capture is the pivot step, so ticket issuing and the email are retried with backoff until they succeed. When a payment call timed out during a provider incident, the saga queried the payment status before deciding, and no customer was charged without receiving tickets. Stuck sagas older than fifteen minutes now raise an alert for the operations team.