Sign in to keep reading
“Multi-Step Processes & Sagas” is free with an account. Your progress and bookmarks follow you across devices.
Sign in to continueNEW: ML Mock & Coaching with a 20+ year experience coach. Save $20 on sessions for Premium.ML Mock & Coaching now available
NEW: ML Mock & Coaching with a 20+ year experience coach. Save $20 on sessions for Premium.ML Mock & Coaching now available
Coordinate complex workflows across multiple services with orchestration, choreography, durable execution, and the Saga pattern for reliable failure compensation.
“Multi-Step Processes & Sagas” is free with an account. Your progress and bookmarks follow you across devices.
Sign in to continueImagine you are building an e-commerce checkout. A customer clicks "Buy" and your system needs to create the order, charge their credit card, reserve inventory, and schedule shipping. Each of those steps lives in a different service. In a monolith, you would wrap the whole thing in a database transaction -- if any step fails, the database rolls everything back automatically. But in a microservices world, there is no single database to coordinate this. Each service has its own data store, and you cannot wrap four independent databases in one ACID transaction.
So what happens when the payment goes through but the inventory service discovers the item is out of stock? You have charged the customer for something you cannot ship. This is the distributed transaction problem, and it comes up constantly in system design interviews.
Traditional databases give you atomicity -- either all changes commit or none do. But the moment your workflow spans multiple services, that guarantee disappears. Two-phase commit (2PC) technically solves this by having a coordinator ask all participants to "prepare" and then "commit," but it has serious downsides: it blocks all participants while waiting for the coordinator, it does not scale, and if the coordinator crashes mid-protocol, participants can be left in a locked state indefinitely.
In practice, almost no production system uses 2PC across microservices. Instead, we embrace the reality that distributed systems will have partial failures and design patterns that handle them gracefully. The two main coordination approaches are choreography and orchestration, and the key failure-handling pattern is the Saga.
In choreography, there is no central brain. Each service publishes events when it finishes its work, and other services listen for those events and act accordingly. The Order Service publishes an OrderCreated event; the Payment Service hears it and charges the card; it then publishes PaymentCharged; the Inventory Service hears that and reserves stock; and so on.
The beauty of choreography is loose coupling. No service knows about the others -- it just publishes what happened and listens for what it cares about. Adding a new step (say, sending a confirmation email) is as simple as deploying a new service that subscribes to the right event. You do not need to modify any existing service.
The downside is visibility. The overall business workflow is scattered across multiple service codebases. When something goes wrong, tracing the flow from "order created" to "shipment scheduled" means hopping between service logs and event streams. There is no single place that shows you the current state of the workflow.
Choreography works best for loosely coupled, eventually consistent flows where you do not need strict ordering or centralized error handling -- things like sending notifications, updating analytics, or syncing search indexes.
See it in practice: The Pub/Sub and Messaging pattern covers the event bus infrastructure that choreography relies on. In the Slack question, message delivery to channels uses event-driven fanout where each component reacts independently. The Fan-Out and Feed Generation pattern uses choreography when a new post triggers independent updates to followers feeds.