Archivedistributed-systems
The Transactional Outbox Removes the Dual-Write Problem
Writing to a database and a broker in one request is not atomic. Write the event to the database instead.
- Published
- Reading time
- 1 min read
A service that updates its database and then publishes an event has two failure points. Crash between them and the system diverges: state changed, event lost, or event published twice.
The outbox pattern
In the same local transaction as the state change, insert a row into an outbox table. A separate relay reads unpublished rows, publishes them, and marks them sent — at least once.
BEGIN;
UPDATE orders SET status = 'paid';
INSERT INTO outbox (id, topic, payload) VALUES (...);
COMMIT;
Relay options
- Polling: simple, adds latency, needs
FOR UPDATE SKIP LOCKEDto parallelize. - CDC (logical replication): Debezium-style tailing of the WAL, low latency, more infrastructure.
Details that matter
- Ordering is per aggregate key, not global.
- Deduplicate on the consumer side; the relay will retry.
- Clean up published rows, but only after the retention window.
Takeaway: make the event part of the same commit as the state. The relay's duplicates are then a consumer problem, not a data-loss problem.