الدرس 2 من 2
Choreography or Orchestration
Two ways to run a saga: services reacting to each other's events, or one component directing the sequence. The choice is mostly about observability and about who owns the flow.
A saga needs something to advance it from one step to the next. Either each service listens for the previous step's event and reacts — choreography — or a coordinator calls each service in turn and tracks progress — orchestration. Both are legitimate, and the choice has more to do with how many steps there are and who needs to see the flow than with any technical property.
The two coordination styles
Choreography
Each service publishes events and subscribes to the ones it cares about. No component owns the sequence.
- No central component to build, run or become a bottleneck
- Adding a reacting service requires no change to existing ones
- Services stay loosely coupled and independently deployable
- The flow exists nowhere: understanding it means reading every service
- Cycles and unintended chains are easy to create by accident
- Compensation across many participants is hard to reason about
Choose when: The flow is short — roughly three steps or fewer — the sequence is stable, and reacting parties may legitimately vary over time.
Orchestration
A coordinator holds the sequence, calls each service, records progress and runs compensations on failure.
- The flow is written down in one readable place
- Progress and stuck sagas are directly observable
- Compensation ordering is explicit and testable
- A component to build, deploy and keep available
- Participants become coupled to the coordinator's contract
- Risks becoming a place where business logic accumulates
Choose when: The flow has four or more steps, involves compensation across several services, or must be explainable to support and to auditors.
The same four-step flow under both styles
The work is identical. What differs is where the sequence lives and whether anyone can see it.
Under choreography, ordering publishes an event, inventory reacts and publishes another, payments reacts to that and publishes a third, and shipping reacts last; no component knows the whole sequence. Under orchestration, a coordinator calls inventory, then payments, then shipping in turn, recording progress after each and running compensations in reverse on failure.
Choreography
Ordering publishes
OrderPlaced
Inventory reacts
publishes StockReserved
Payments reacts
publishes PaymentTaken
Shipping reacts
nobody sees the whole
Orchestration
Coordinator
owns the sequence and state
Inventory
called, returns
Payments
called, returns
Shipping
called, returns
Making a saga operable
- 1
Persist saga state with an explicit status per step
Started, completed, failed, compensating, compensated. This is what support and reconciliation read, and it is what recovery uses after a crash.
- 2
Give every saga a deadline
A saga waiting on a step that will never complete must eventually give up and compensate. Without a timeout, stuck sagas accumulate silently and are discovered by a customer.
- 3
Make compensations idempotent and independently retryable
A compensation that fails must retry without repeating the ones that succeeded. Compensations run in the worst conditions — something has already gone wrong — so they must be the most robust code in the flow.
- 4
Alert on sagas stuck beyond their expected duration
Not on individual failures, which are normal, but on sagas that have not reached a terminal state in the time they should. This is the metric that catches a broken participant.
- 5
Provide a human path for the cases automation cannot resolve
A compensation that keeps failing needs a person. An admin view showing saga state with a manual resolution action turns a support escalation into a two-minute task, and it will be used more than you expect.
In practice
Moving one flow from choreography to orchestration
A subscription business ran sign-up as a choreographed saga across six services. It worked, until support began receiving "my account is half set up" reports that took an engineer 40 minutes each to diagnose.
Constraints
- Six participating services, no component knowing the whole flow
- Roughly 25 stuck sign-ups per week out of 4,000
- Support could not answer "what happened?" without engineering
- The flow itself was correct; the problem was visibility
Decision
Introduce an orchestrator for the sign-up flow only, leaving the other choreographed flows alone. The orchestrator owns sequence, timeouts and compensation, and exposes saga state to a support screen.
Why
The flow had six steps, compensation across four services, and a support audience — every criterion pointing to orchestration. Diagnosis time was the concrete cost: 25 incidents a week at 40 engineer-minutes each is roughly two engineer-days a week spent reconstructing sequences that a coordinator would simply have recorded.
What it cost
The orchestrator is a new component to run and a new dependency for six services, and the team had to actively resist proposals to put eligibility rules and pricing logic into it — they added a review rule that the orchestrator may not contain a conditional based on domain data. Diagnosis time fell from 40 minutes to under two, and support resolved most cases without engineering. Other flows stayed choreographed, because two or three steps with no support audience do not justify the component.
Choosing the coordination style for a new flow
As a developer
Prefers choreography, because it adds no component, keeps services loosely coupled, and follows the event-driven style the system already uses.
As an architect
Asks three questions first: how many steps, who will need to explain a failure, and does compensation span more than two services. Choreography is genuinely the lighter option for short flows and becomes the more expensive one at six steps, because the cost moves from build time to every future incident. The style should be chosen per flow rather than adopted as a system-wide standard — most systems benefit from having both.
A saga's compensating action fails repeatedly — the refund provider is rejecting the request. What should the system do?RevealHide
Retry with backoff for a bounded period, because many such failures are transient, and then stop and escalate to a human rather than retrying indefinitely. Three things must be true for that escalation to work: the saga is left in an explicit `compensation_failed` state rather than being retried forever or silently abandoned; someone is alerted, since a failed compensation usually means a customer is owed money; and there is an interface where a person can see the state and record a manual resolution. It is worth being direct about the underlying point — a saga cannot guarantee that compensation succeeds, only that it is attempted and recorded. Designing for the case where automation gives up is part of the pattern, not an admission that it failed.
Key takeaways
- Choreography suits short, stable flows; orchestration suits longer flows and anything support must explain.
- The deciding question is usually who has to diagnose a stuck case and how long it takes them.
- Keep an orchestrator responsible for sequence and compensation only, never for domain decisions.
- Persist saga state per step, give every saga a deadline, and alert on sagas that never reach a terminal state.
- Design the path for compensations that fail: an explicit state, an alert, and a human resolution route.