NOTE
2.8 Transactional Outbox / Local Message Table
How to commit business state and an outgoing event in one local database transaction, then asynchronously publish with retries and idempotent consumption.
This is a historical learning note and may contain outdated or incomplete understanding.
1. The Dual-Write Problem
Suppose service A creates an order and must tell service B to grant points. These two operations cannot safely be implemented as:
- commit the order;
- publish a message once.
If the process crashes between the two, the order exists but the event is lost.
2. Transactional Outbox Pattern

Service A uses one local transaction:
BEGIN;
-- write business state
-- insert outgoing event into outbox table
COMMIT;
A separate publisher scans or streams committed outbox rows and sends them to the message broker. Successfully published rows are marked or removed according to the implementation.
Service B consumes the event and applies its own local transaction. Because delivery may repeat, B must make processing idempotent, for example with a processed-message key or a naturally idempotent state transition.
3. Properties
- avoids the producer-side database/MQ dual-write gap;
- decouples downstream processing from the producer transaction;
- normally gives at-least-once publication/consumption semantics;
- requires cleanup, retry policy, lag monitoring, and poison-message handling.
Change-data-capture can replace explicit polling while preserving the same core idea: the outgoing event is committed atomically with the business data.