Outbox
The outbox pattern (Figure 9-11) ensures reliable publishing of domain events using the following algorithm:
• Both the updated aggregate’s state and the new domain events are committed in the same atomic transaction.
• A message relay fetches newly committed domain events from the database.
• The relay publishes the domain events to the message bus.
• Upon successful publishing, the relay either marks the events as published in the database or deletes them completely.
![]() |
When using a relational database, it’s convenient to leverage the database’s ability to commit to two tables atomically and use a dedicated table for storing the messages, as shown in Figure 9-12.
When using a NoSQL database that doesn’t support multidocument transactions, the outgoing domain events have to be embedded in the aggregate’s record. For example:
{
"campaign-id": "364b33c3-2171-446d-b652-8e5a7b2be1af",
"state": {
"name": "Autumn 2017",
"publishing-state": "DEACTIVATED",
"ad-locations": [
...
]
...
},
"outbox": [
{
"campaign-id": "364b33c3-2171-446d-b652-8e5a7b2be1af",
"type": "campaign-deactivated", "reason": "Goals met", "published": false
}
]
}
In this sample, you can see the JSON document’s additional property, outbox, con‐ taining a list of domain events that have to be published.
Fetching unpublished events
The publishing relay can fetch the new domain events in either a pull-based or push- based manner:
Pull: polling publisher
The relay can continuously query the database for unpublished events. Proper indexes have to be in place to minimize the load on the database induced by the constant polling.
Push: transaction log tailing
Here we can leverage the database’s feature set to proactively call the publishing relay when new events are appended. For example, some relational databases enable getting notifications about updated/inserted records by tailing the databa‐ se’s transaction log. Some NoSQL databases expose committed changes as streams of events (e.g., AWS DynamoDB Streams).
It’s important to note that the outbox pattern guarantees delivery of the messages at least once: if the relay fails right after publishing a message but before marking it as published in the database, the same message will be published again in the next iteration.
Next, we’ll take a look at how we can leverage the reliable publishing of domain events to overcome some of the limitations imposed by aggregate design principles.