Outbox (architectural)
The buffer table that turns two uncoordinated writes (DB + broker) into a single atomic write on the DB side.
Problem
Without broker XA (Kafka), how to guarantee that a business side effect (order creation) and its broker-published message both arrive or neither — without locking the application if the broker is down?
Forces
- A broker write during a DB transaction is not transactional.
- A broker outage must not block order intake in the application.
- A publish retry must be idempotent on the broker side.
- The poller must have enough throughput to not accumulate backlog.
Solution
Create an `outbox` table (id, aggregate_type, aggregate_id, payload, status, created_at). The producer inserts its message into `outbox` within the same transaction as business changes (one COMMIT). A dedicated poller — often Debezium CDC on the outbox table — reads new rows and publishes to the broker. On successful publish, status flips to `SENT`. On failure, retry with backoff. The PK or a stable message_id ensures broker-side idempotency.
EDI implementation
In EDI, Outbox is the dominant pattern to wire ERP → Kafka EDI hub. The ERP inserts the 'OrderConfirmed' event into `outbox` within the transaction that confirms the order. Debezium reads PostgreSQL WAL, publishes on `edi.orders.confirmed`. The EDI hub consumes and emits an ORDRSP to the partner. Bonus: the outbox table also serves as a message store for replay and audit — useful in case of a broker export incident.
Anti-patterns
- Outbox without index on status / created_at — the poller scans the whole table each cycle.
- Outbox without purge — the table grows indefinitely and the poller slows down.
- Outbox without an idempotency message_id — a retry duplicates the message on the broker.
- Single-threaded poller with high throughput — the poller becomes the bottleneck.
Related patterns
- Transactional Client — corresponding code abstraction.
- Transactional Channel — parent topological concept.
- Change Data Capture — typical poller mechanism.
- Guaranteed Delivery — overall goal.
Sources
- Microsoft Azure Architecture — Outbox pattern. learn.microsoft.com/en-us/azure/architecture/patterns/outbox
- Debezium — Outbox event router. debezium.io/documentation/reference/transformations/outbox-event-router.html