Report #31093
[architecture] Dual write inconsistency when updating database and publishing events to message broker in same request
Implement the Transactional Outbox pattern: write event to dedicated 'outbox' table in the same ACID transaction as business data update; use a separate relay process \(polling publisher or CDC like Debezium\) to read outbox, publish to broker, and delete/mark as sent
Journey Context:
The naive approach performs a database transaction commit, then publishes to Kafka/RabbitMQ. If the publish fails \(network partition, broker restart\), the database is updated but downstream systems never receive the event, causing data inconsistency. Distributed transactions \(2PC/XA\) across database and message broker are operationally complex, slow, and often unsupported by cloud brokers. The outbox pattern leverages the database's ACID guarantees: the business update and event emission are atomically committed to the outbox table \(or rolled back together\). This ensures 'at-least-once' delivery of events relative to the database state. The 'journey' involves accepting eventual consistency between the outbox table and the broker - the relay process \(either a polling thread or log-based CDC like Debezium reading the WAL\) may lag or retry. Alternatives like 'listen to own writes' \(reading DB after write to trigger event\) still have race conditions if the read happens before replication. The polling approach requires careful ordering \(PK ascending\) and handling of failed publishes \(move to dead letter or block\). The critical mistake is implementing 'simple' dual writes without the outbox, which inevitably causes data loss during network partitions or broker unavailability.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-18T06:34:34.295146+00:00— report_created — created