Choreography vs orchestration

3 min read
On trails:EDAPATstep 3/7

Placing an order touches several services: Inventory reserves stock, Payments takes the money, Shipping books the delivery. Someone has to make those steps happen in the right order. In choreography nobody does: each service reacts to the events of the others. In orchestration one component, the orchestrator, holds the workflow and tells each service what to do next.

Choreography

Orders publishes OrderPlaced. Inventory reacts and publishes StockReserved. Payments reacts to that and publishes PaymentReceived, and Shipping reacts to that. Every step is an eventEvents, commands and queriesThree kinds of message: an event states a fact, a command asks one owner to act, a query only reads.Opens in a new tab that any service may subscribe to.

Choreography: Orders publishes OrderPlaced, Inventory reacts and publishes StockReserved, Payments reacts and publishes PaymentReceived, Shipping reacts. No service coordinates the others. Orders OrderPlaced Inventory StockReserved Payments PaymentReceived Shipping each service knows only the event it reacts to and the event it publishes
Choreography. The flow exists only as a chain of subscriptions.

There is no coordinator to fail and no central code to change. Adding a consumer, for example Notifications reacting to PaymentReceived, touches nothing else. The cost is that the workflow is written down nowhere. To learn what happens after an order is placed, you read the subscriptions of every service. Microsoft’s saga guidance lists the same drawbacks: it is hard to see which events each participant responds to, new steps make the flow confusing, services can end up depending on each other in a cycle, and testing needs all of them running.

Orchestration

The orchestrator sends a command to one service, waits for the reply event, and then sends the next. It keeps the state of each order’s workflow: which step it is on, and what has succeeded.

Orchestration: an order orchestrator sends ReserveStock to Inventory, ChargePayment to Payments and BookDelivery to Shipping, and decides the next step from each reply. Order orchestrator holds the state ReserveStock ChargePayment BookDelivery Inventory Payments Shipping each service replies with an event, and the orchestrator decides the next step
Orchestration. The flow is in one place.

Now the whole flow is in one place, which makes it easy to read, to test, and to change. Services stay simple, because each one only handles its own commands. The orchestrator is also a component that can fail or become a bottleneck, it is coupled to every service it calls, and its state must survive a restart. Libraries such as NServiceBus and MassTransit provide saga support for holding that state.

AspectChoreographyOrchestration
Who knows the whole flowNo oneThe orchestrator
What services exchangeEventsCommands and reply events
Adding a stepAdd a subscriber, but the flow becomes harder to followChange the orchestrator
Seeing where one order isJoin the logs of every serviceRead the orchestrator state
Single point of failureNone addedThe orchestrator
FitsFew services, simple flowsMany steps, branches, failure handling
Table 1. Choreography and orchestration

Choosing

Start with choreography for two or three steps and no failure path. Move to an orchestrator when the flow has branches, when it needs a timeout or a retry decision, or when someone has to answer “where is order 4711?”. Either one can be used to run a sagaSagasA workflow made of local transactions, with an undo step for each one.Opens in a new tab, which adds the undo steps for a failure partway through. Both rely on the reliability basics: idempotent consumersIdempotent consumersA consumer that gives the same result whether a message arrives once or five times.Opens in a new tab and a way to correlate every message with its order (see traceabilityTraceabilityLog the whole reasoning trace, so any answer can be explained afterwards.Opens in a new tab).


Sources