Saga
Maintain data consistency across services without a distributed transaction, by splitting the work into local transactions each paired with a compensating action.
Placing an order might charge a payment, reserve stock and book a shipment. Each of those lives in a different service with its own database.
Within one database you would wrap all of it in a transaction and roll back on failure. Across services you cannot. A distributed transaction holds locks over the network and stops everything if the coordinator dies, so it is avoided in practice.
A Saga breaks the work into steps. Each step commits on its own, in its own service. Each step also has an undo action. If a later step fails, the earlier ones are undone in reverse.
One point matters most in interviews. Undoing is not rolling back. The payment really happened, and anyone looking would have seen it. The refund is a separate action that comes after. You get the right final outcome, not a hidden middle.
What the interviewer is probing.
1. "Why does Saga exist?" *Probing:* the motivation. *Stalls:* "Transactions." *Moves up:* a distributed transaction across services is impractical, so a sequence of local transactions with compensations takes its place.
2. "Choreography or orchestration?" *Probing:* the two styles. *Stalls:* "The same." *Moves up:* choreography is event-driven with no coordinator and becomes hard to follow; orchestration centralises the flow, which is clearer but is another component.
3. "What is a compensating transaction?" *Probing:* the key detail. *Stalls:* "A rollback." *Moves up:* a business-level reversal — issuing a refund, not undoing a commit, since the original was already visible.
4. "What must the business accept?" *Probing:* the honest consequence. *Stalls:* "Nothing." *Moves up:* eventual consistency and visible intermediate states, which has to be a product decision rather than a technical one.
Booking a trip through separate airline, hotel and car sites. Each booking confirms on its own. If the car falls through you do not un-book the flight — you cancel it, which may cost a fee and is visible on your statement. The trip ends up consistent; the intermediate mess really happened.
Key Concepts
// Orchestration-based Saga: one coordinator owns the sequence and the
// compensations. Each step is a local ACID transaction in its own service;
// there is no distributed transaction and no two-phase commit.
public class OrderSaga {
private final PaymentClient payments;
private final InventoryClient inventory;
private final ShippingClient shipping;
private final SagaLog log; // durable: survives a crash mid-saga
public void execute(Order order) {
// Every completed step is recorded BEFORE the next one starts, so a
// crash can be resumed or compensated from the log rather than guessed at.
Deque<Runnable> compensations = new ArrayDeque<>();
try {
String paymentId = payments.charge(order.customerId(), order.total());
log.stepCompleted(order.id(), "PAYMENT", paymentId);
compensations.push(() -> payments.refund(paymentId));
String reservationId = inventory.reserve(order.items());
log.stepCompleted(order.id(), "INVENTORY", reservationId);
compensations.push(() -> inventory.release(reservationId));
String shipmentId = shipping.schedule(order);
log.stepCompleted(order.id(), "SHIPPING", shipmentId);
log.sagaCompleted(order.id());
} catch (Exception failure) {
// Compensate in REVERSE order. These are semantic undos, not
// rollbacks: the charge really happened and the refund is a new,
// separately visible transaction.
log.sagaCompensating(order.id(), failure.getMessage());
while (!compensations.isEmpty()) {
Runnable undo = compensations.pop();
try {
undo.run();
} catch (Exception e) {
// A failed compensation cannot be retried forever in-line.
// Park it for operators — this is the case that wakes people up.
log.compensationFailed(order.id(), e);
}
}
log.sagaCompensated(order.id());
}
}
}
// Compensations must be IDEMPOTENT: retries and redeliveries mean refund()
// will be called more than once for the same paymentId, and it must only
// ever move money once.