Outbox Pattern
How a service changes its database and publishes an event without losing either: write both in one transaction, relay the outbox to the broker by polling or change data capture, and make consumers idempotent.
Overview
Most services that own data also need to tell other services when it changes: an order was placed, a payment captured, a user deleted. The obvious code writes to the database and then publishes a message to a broker such as Kafka or RabbitMQ. That is two writes to two systems with no transaction spanning both, so a crash, a timeout or a broker outage between them leaves the two out of step. This is the dual-write problem.
The transactional outbox fixes it by making the event part of the database write. The service inserts the event into an outbox table in the same transaction as the business change, so either both are saved or neither is. A separate message relay then reads the outbox and publishes each event to the broker, retrying until the broker accepts it. Chris Richardson's microservices.io catalog describes the pattern, and Debezium ships a ready-made router for it.
The price is that events can now be published more than once, and consumers must cope. The rest of this topic is about the relay, duplicates and ordering.
What you will be able to do
- Explain the dual-write problem and why retries or reordering the writes do not fix it.
- Design the outbox table and the transaction that fills it, in SQL.
- Choose between a polling relay and change data capture, and name the operational risks of each.
- Make consumers idempotent with an inbox table, and state what ordering the pattern gives.
- Compare the outbox with two-phase commit, event sourcing and listening to yourself.
Key concepts
- Dual-write problem
- Transactional outbox
- Message relay
- Polling publisher
- Log tailing (CDC)
- At-least-once delivery
- Idempotent consumer (inbox)
- Per-aggregate ordering
Interview questions
- What is the dual-write problem, and why can't you fix it by reordering or retrying?
- Walk through the transactional outbox pattern.
- Polling publisher or change data capture: how do you choose?
- How do consumers deal with duplicate events?
- What ordering does the outbox pattern guarantee?
- What can go wrong when running Debezium for the outbox in production?
- How does the outbox compare with event sourcing and listen-to-yourself?
Sign up free to read the full topic
More System Design topics
Start free on Cariara · Coding problems · System design studio