10.2 Transactional Outbox
Atomically send a message and update the databaseThis pattern is based on the Transactional Outbox by Richardson [20, p. 97, 165] and Deenadayalan [166].
10.2.1 Context
A message and a database operation need to be done as part of the same transaction – the message must be sent iff the operations succeed – and a two-phase commit1 cannot be used, either because of incompatibility with the underlying technologies, payload differences, or availability concerns [20, p. 112, 169].
10.2.2 Solution
Store the message in the database as a part of the transaction in an outbox table (see fig. 28). An outbox processor reads messages from the outbox table and sends them to the message broker. The processor marks the messages as sent or deletes them to avoid reprocessing.
Richardson highlights two methods for implementing the outbox processor:
The Polling publisher periodically polls the database, trading simplicity for increased load and traffic [20, p. 98, 170]
The Transactional log tailing is a more efficient method which reads the database’s commit log and propagates that instead [20, p. 99, 171]
10.2.3 Potential issues
Depending on the implementation, this can cause increased database load, which can cause it to become a bottleneck. It also introduces additional complexity due to a need for an extra processor and additional latency in message delivery.
This pattern does not prevent duplicate messages; handling those requires additional measures.
10.2.4 Example
Example eshop needs to send a confirmation email when users register. If the confirmation email has not been delivered but the account has been created, the user might need to ask for a password reset. To avoid this, the service handling registration writes a message to an outbox as part of the user creation database transaction. The message is not removed from the outbox until the service receives a confirmation that the email has arrived or that the email address does not exist.
10.2.5 Related patterns
If the transaction needs to span multiple services, use the Saga pattern (see § 10.3)
If there is no update to the database, using Queue-based Load Leveling for guaranteed delivery might be more efficient (see § 7.2)
10.2.6 Further reading
- Inbox and Outbox pattern [58]