cconnected.
Understand the pattern. Find your own way.Find your starting point
Your learning feed/Idea 205 of 218
Ideas this builds on
High-level design205 / 218

Coordinate a workflow without one global transaction

Picture

Reserve inventory, authorize payment, then arrange shipping. Each service can commit locally, but there is no single simple rollback across them.

Predict

Is compensation identical to rolling back an uncommitted database transaction?

Walk through the small example

No, it is a new business action. Compensation can be imperfect, delayed, and independently fallible.

Mental model and runnable Python model

A saga is a sequence of local transactions with explicit compensating operations. Orchestration uses a coordinator that records progress and commands the next step; choreography reacts to events and can distribute control but make the overall workflow harder to follow. Define idempotency, timeouts, ownership, durable state, and manual reconciliation. Avoid calling compensation a guarantee that every effect vanishes. The synchronous model below demonstrates order and reverse-order compensation only; real sagas need durable coordination and recovery.

What the function promises: Each step is (do, compensate). Successful earlier steps are compensated in reverse order if a later do raises. A failed do is assumed to leave no committed effect. Compensation errors are collected, not hidden.

def run_saga(steps):
    completed = []
    try:
        for do, compensate in steps:
            do()
            completed.append(compensate)
        return True, []
    except Exception as failure:
        errors = [failure]
        for compensate in reversed(completed):
            try:
                compensate()
            except Exception as error:
                errors.append(error)
        return False, errors

log = []
def fail_shipping():
    raise RuntimeError("Shipping unavailable")
ok, errors = run_saga([
    (lambda: log.append("reserve"), lambda: log.append("release")),
    (fail_shipping, lambda: log.append("cancel shipping"))
])
assert not ok and len(errors) == 1
assert log == ["reserve", "release"]

Work and storage: O(number of steps plus attempted compensations), excluding service work. Real durable workflow history grows with operations and retries.

When to recognize it: Store workflow state, retry safely, and make unresolved cases visible. A saga does not make intermediate states invisible to everyone.

Check before applying it: Sagas need durable progress and uncertain-outcome handling; compensation can itself fail.

Change one rule

A failing service times out after committing its effect. Is the sample assumption still valid?

See what changes

No. Query or reconcile by stable operation ID before choosing compensation or retry. An uncertain timeout is not proof that the failed step had no effect.

Connect

Commit the change and its event together: Durable local intent is one building block for cross-service workflows.

Design a vending machine: A failed dispense after payment is a concrete example of imperfect compensation.