# Sagas

> A multi-service transaction as a sequence of local steps with compensating actions.

Concept · Async work & messaging · https://levelcode.org/concepts/saga-pattern

When a business operation spans several services — reserve stock, charge a card, schedule delivery — there's no single database transaction that covers them all. A **saga** splits the operation into a sequence of **local transactions**, one per service. If a step fails, the saga runs **compensating actions** that undo the steps already completed.

## Example: placing an order

| Step | Service | Compensation |
|---|---|---|
| 1. Create order (pending) | Orders | Cancel the order |
| 2. Reserve stock | Inventory | Release the reservation |
| 3. Charge payment | Payments | Refund |
| 4. Confirm order | Orders | — (final step) |

If step 3 fails, the saga releases the stock and cancels the order. If step 4 can't happen after a successful charge, it refunds.

## Orchestration or choreography

- **Orchestration:** a coordinator (an "order saga" service or a workflow engine such as Temporal) tells each service what to do and tracks progress in its own state. Easy to follow and change; the coordinator is one more component.
- **Choreography:** each service reacts to the previous service's event ("stock.reserved" → payments charges). No coordinator, but the overall flow is spread across services and harder to see.

Most teams prefer orchestration once a saga has more than two or three steps.

## Making sagas reliable

- Steps and compensations communicate through events published with a [transactional outbox](https://levelcode.org/concepts/transactional-outbox), so no step's completion is lost.
- Every step and compensation must be **idempotent**, because messages are delivered at least once ([idempotent consumers](https://levelcode.org/concepts/idempotent-consumers)).
- Compensations are **semantic**, not rollbacks: a refund is a new transaction, and an email already sent can only be followed by an apology.
- Intermediate states are visible. Others can see the order as "pending" while the saga runs, so design the states and the UI for it.

## Sagas versus two-phase commit

[Two-phase commit](https://levelcode.org/concepts/two-phase-commit) gives atomicity across participants but blocks if the coordinator fails and isn't available across external APIs such as payment providers. Sagas give up isolation and instant atomicity in exchange for availability and loose coupling — usually the right trade between services.
