Skip to content
hashkey.bond

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 LOCKED to 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.