BeCuriouzBeCuriouz

Learn something new every day

✍️ Blogs
📬

The bug hiding in "save order, then publish event"

💡 You can't atomically update a database and publish to a message broker; the outbox pattern turns that risky dual write into a single transaction plus a reliable relay.

Almost every microservice does this: write a row to the database, then publish a message ("OrderPlaced") to a broker like Kafka so other services react. It looks atomic. It isn't. This is the dual write problem — two separate systems, no shared transaction. If the app crashes after the database commit but before the publish, the order exists forever with no event. Flip the order and you can publish an event for an order that never actually saved. Retries don't fix it; they just create duplicates.

The transactional outbox pattern sidesteps this with one trick: don't publish to the broker at all inside the request. Instead, insert the event as a row into an outbox table in the same database transaction as the business data. Now it's genuinely atomic — either both the order and its event commit, or neither does.

A separate relay process then ships those rows to the broker — either by polling the outbox table, or (better) by tailing the database's transaction log via change data capture (CDC), as tools like Debezium do. The relay guarantees at-least-once delivery, so consumers must be idempotent, but the impossible "data saved, event lost" state is gone.

📬 The bug hiding in "save order, then publish event" — BeCuriouz