dev-tools

Saga Pattern

The saga pattern is a way of keeping data consistent across services when no single database transaction can span them. Instead of one atomic commit that either fully succeeds or fully rolls back, a saga breaks the work into a sequence of local transactions, each committed independently in its own service, and pairs each step with a compensating action that semantically undoes it if a later step fails. A subscription upgrade in a typical SaaS backend illustrates it: charge the card, update the entitlement, provision the extra seats, send the receipt. Four services, four separate databases, and no shared transaction. If provisioning fails after the charge succeeded, nothing can roll the charge back in the database sense — the money moved. The compensating action is a refund, which is a new forward transaction that leaves both records in place. That is the defining property and the one people misread: compensation is semantic, not literal. There are two coordination styles. Choreography has each service publish an event and the next react to it, which keeps services decoupled but scatters the flow across the codebase, so no single place describes what the transaction actually does. Orchestration puts one component in charge of calling each step and invoking compensations on failure, which makes the flow readable and testable at the cost of a component that must itself be made durable — it cannot lose its state mid-saga. Most teams start with choreography for two or three steps and move to orchestration when the sequence grows or when someone has to debug it. Sagas trade atomicity for availability, and the cost is that intermediate states are visible: for a period, a customer has been charged and does not yet have the seats. The system must be designed so that state is legible rather than surprising. Every step also has to be idempotent, because retries are guaranteed and a compensating action that runs twice must not refund twice. Practical note: give every saga a persisted state record with an id, a current step and a terminal outcome, and make compensations idempotent by keying them on that id. Sagas fail in production not because compensation is hard to write but because nobody can answer which step a stuck transaction is on.

Related terms

More Dev Tools terms