Transactional Event Publication and Outbox
Guarantee event delivery with the event publication registry and transactional outbox pattern.
Why Events Get Lost
In an event-driven Spring Modulith application, modules talk to each other by publishing application events. A module raises an event inside a transaction, and listeners in other modules react to it.
The danger: by default, when you publish an event and a listener processes it asynchronously (or in a separate transaction), the listener's work can fail after the publisher already committed. The result is a lost event — the publisher's state changed, but the downstream side effect never happened.
- Publisher commits an
Orderas PAID. - The async listener that sends a confirmation email crashes.
- Nobody retries — the customer never gets the email.
This lesson shows how Spring Modulith's Event Publication Registry implements the transactional outbox pattern to guarantee delivery.
The Transactional Outbox Pattern
The transactional outbox pattern solves the dual-write problem: you must atomically (1) change your business state and (2) record that an event needs to be delivered.
Instead of trying to write to the database and a message broker in one transaction (impossible without distributed transactions), you write both into the same database in the same local transaction:
- The business change (e.g. the order row).
- A row in an outbox table describing the event.
A separate process then reads unprocessed outbox rows and delivers them, marking each as completed. Because the outbox write shares the business transaction, an event is recorded if and only if the business change committed.
All lessons in this course
- Application Modules and Boundary Verification
- Internal Application Events and Listeners
- Transactional Event Publication and Outbox
- Module Integration Testing and Scenarios