BackendBench
Coffee

Unravel โ€บ Java concepts โ€บ Design patterns and architecture

I/O and data

Sagas and distributed transactions

A business process that spans several services cannot use one database transaction.

Learn these first

At a glance

Mental model

Booking a holiday from separate companies: flight, hotel, car.

What happens, in order
  1. 1Each service performs a local transaction and then triggers the next step (by an event or a command)A failure triggers compensations in reverse order: refund the payment, release the stock, cancel the order.
  2. 2Choreography: services react to each other events with no central coordinatorSimple for two or three steps, hard to follow for many.
  3. 3Orchestration: one coordinator (a saga class, a workflow engine such as Temporal or Camunda, or Axon sagas) keeps the state and sends commandsIt is easier to see, test and monitor.
  4. 4Each step and each compensation must be idempotent and retryable, because messages repeat and the coordinator may restart
Remember
Watch out
Compensations that are not idempotentIgnoring intermediate states in the user interfaceNo timeout handlingUsing a distributed (two-phase) transaction across services instead of a saga without understanding the cost
Example (highlighted lines explain it)
@Sagapublic class OrderSaga {    @StartSaga    @SagaEventHandler(associationProperty = "orderId")    public void on(OrderPlaced event, CommandGateway commands) {        commands.send(new ReserveStock(event.orderId(), event.items()));    }    @SagaEventHandler(associationProperty = "orderId")    public void on(StockRejected event, CommandGateway commands) {        commands.send(new CancelOrder(event.orderId(), "out of stock"));    }}
  1. line 1 uses Saga, the core of Sagas and distributed transactions
  2. line 2 uses Saga, the core of Sagas and distributed transactions
  3. line 3 uses StartSaga, the core of Sagas and distributed transactions
  4. line 4 uses Saga, the core of Sagas and distributed transactions
  5. line 9 uses Saga, the core of Sagas and distributed transactions
Read the full explanation (about 2 min)

A business process that spans several services cannot use one database transaction. A saga splits it into local steps, and each step that already succeeded has a compensating action to undo it if a later step fails.

A mental model

Booking a holiday from separate companies: flight, hotel, car. If the car company refuses, you cancel the hotel and the flight one by one, instead of one magic undo that covers everyone.

How it works

Each service performs a local transaction and then triggers the next step (by an event or a command). A failure triggers compensations in reverse order: refund the payment, release the stock, cancel the order.

Choreography: services react to each other events with no central coordinator. Simple for two or three steps, hard to follow for many.

Orchestration: one coordinator (a saga class, a workflow engine such as Temporal or Camunda, or Axon sagas) keeps the state and sends commands. It is easier to see, test and monitor.

Each step and each compensation must be idempotent and retryable, because messages repeat and the coordinator may restart.

Going deeper

There is no isolation between steps: other requests can see half-finished state (a reserved but unpaid order). Use semantic locks (a PENDING status) and design screens and queries for intermediate states.

Some actions cannot be undone (an email sent, a parcel shipped). Order steps so that irreversible ones come last, and use "compensation" such as an apology or a return label where reversal is impossible.

Timeouts are part of the design: a saga that waits forever for a reply holds the process hostage. Define deadlines and what to do when they pass.

Under the hood

A saga log (database table or event store) persists the current step and data. On restart the coordinator loads unfinished sagas and continues or compensates. Workflow engines replay a deterministic workflow function from its event history to rebuild state, which is why workflow code must avoid randomness and wall-clock reads.

Common mistakes

  • Compensations that are not idempotent.
  • Ignoring intermediate states in the user interface.
  • No timeout handling.
  • Using a distributed (two-phase) transaction across services instead of a saga without understanding the cost.

How Unravel recognises it

When you paste code, Unravel looks for these signs of sagas and distributed transactions. Spotting them yourself is a good habit when you read unfamiliar code:

Part of a learning path

Related concepts

Frequently asked questions

What is Sagas and distributed transactions?

A business process that spans several services cannot use one database transaction. A saga splits it into local steps, and each step that already succeeded has a compensating action to undo it if a later step fails.

What are the most common mistakes with Sagas and distributed transactions?

Compensations that are not idempotent. Ignoring intermediate states in the user interface. No timeout handling. Using a distributed (two-phase) transaction across services instead of a saga without understanding the cost.

How can I see Sagas and distributed transactions in real code?

Paste your own Java into Unravel and it will point out where sagas and distributed transactions appears, explain how it works at the detail level you choose, and draw the flow of the code around it.