The Runtime Theory
mediumApplicationDSA#backend#transactions#messaging#reliability

Explain the outbox pattern

Probes whether you know the dual-write problem and the mechanism that fixes it — the event as a row in the same transaction, plus an at-least-once relay.

The Runtime Theory Team2 min readasked at stripe · netflix · amazon

This question tests whether you understand the dual-write problem — the fundamental reason the outbox pattern exists at all. The interviewer wants you to name the failure mode first, then walk the mechanism that eliminates it.

The mental model: make the side effect part of the transaction that creates it.

The problem: you have a database transaction that inserts an order, and you also want to publish an "order created" event to a queue. If you publish after committing, and the commit succeeds but the publish fails, the event is lost forever — the customer gets an order nobody knows about. If you publish before committing, consumers can observe events for orders that then roll back. No ordering of commit-then-publish is safe, because two systems cannot be atomic together.

The outbox pattern makes the message a row in the same database, written inside the same transaction: alongside the order INSERT, you INSERT into an outbox table — event type, payload, status. Atomicity now comes from the database: either the order and the outbox row both commit, or neither does. Publishing becomes a relay: a poller reads committed outbox rows in batches, publishes them to the queue, and marks them published or deletes them. The relay is a batch job — periodic, resumable, idempotent — which is why it shows up in traces as a recurring poller rather than an inline step.

The key property: the relay is naturally at-least-once. It can crash between publish and mark, and the row gets published twice — so consumers must dedupe on event ID, and the outbox row should carry an idempotency key the consumer can check. Ordering is the second concern: the relay should read rows in commit order (monotonically increasing ID or commit timestamp), so consumers observe events in creation order, even when the poller batches.

Tradeoffs and edge cases: the outbox adds a table, a poller, and latency — events are only as real-time as the polling interval. Alternatives: a CDC connector (Debezium) tailing the transaction log instead of polling, or two-phase commit, which is expensive and operationally fragile. The edge case interviewers probe: rows that fail to publish forever. You need retry with backoff and a dead-letter path, and the mark-published update must happen in the relay's own transaction so a crash can't cause the same row to be published twice in one pass. At-least-once delivery plus consumer-side dedupe is the whole game.

This answer walks

Follow-ups they'll push on

  1. 01Why can't you just publish the event after the transaction commits?
  2. 02How does the relay guarantee ordering?
  3. 03What happens when the relay crashes between publish and mark?

More interviews in this topic

One dispatch a week

The trace behind each question, the tradeoff that explains it, and one technical dispatch per week — no noise.

One technical dispatch per week. No noise.