intermediate 2 min answer

A service must update its database and publish an event. Why is doing both directly incorrect, and what does the outbox pattern guarantee?

outboxdual-writeatomicityat-least-oncetwilioconceptual
Show the full answer Hide the answer

Why the direct approach is incorrect

The two writes are not atomic. Whatever order they occur in, a failure between them leaves the systems inconsistent:

  • Database first, then publish. The service crashes after committing and before publishing. The state changed and nobody was told — a message is recorded as sent and no delivery is triggered.
  • Publish first, then database. The service crashes after publishing and before committing. Consumers act on an event describing a state change that did not happen.

Neither is recoverable by retry, because the service does not know which side succeeded. And crucially, the inconsistency is silent — nothing errors, and the divergence is discovered later by a customer or by reconciliation.

What the outbox guarantees

The event is written to a table in the same local transaction as the state change. Either both commit or neither does. A separate process reads the outbox and publishes.

That gives: if the state changed, the event will be published.

What it does not guarantee

Exactly-once delivery. The publisher may crash after publishing and before marking the row as sent, so the event is published again. Delivery is at-least-once, which forces the complementary requirement: consumers must be idempotent, keyed on a business identifier or an event id.

Attempting exactly-once across a network to systems you do not control is not achievable, and designing for at-least-once with idempotent consumers is the correct response rather than a compromise.

The operational details that matter

  • Ordering, if required, comes from publishing in outbox insertion order per key — not globally.
  • Outbox growth needs a cleanup process, or the table becomes the largest in the database.
  • Publisher lag monitored, since a stalled publisher means state changes that nobody hears about, with no error anywhere.
  • Change data capture can replace the polling publisher, reading the database log directly — lower latency and no query load, at the cost of another component.

The alternative worth considering

Do not publish at all where a database-backed queue suffices. At moderate volume, enqueueing work in the same database and transaction removes the dual-write problem entirely rather than mitigating it — no outbox, no broker, no reconciliation. The outbox exists because an external broker was chosen; if that choice is not required, the problem does not arise.