Transactional Outbox diagram template
Write business data and an event in one transaction, then relay the event reliably.
About this design
The dual write problem is simple to state and surprisingly easy to ship: a service updates its database and then publishes an event, and a crash between the two leaves them disagreeing. The transactional outbox removes the gap. In one local transaction the service writes its business change and also inserts a row describing the event into an outbox table. A separate relay process reads unpublished outbox rows and sends them to the message broker, marking each as sent afterwards. If the relay crashes it simply resumes, so every event is published at least once, and consumers deduplicate using the event id. Use this template to discuss polling versus log tailing for the relay, ordering per aggregate, cleaning up old outbox rows, and why this pattern is almost always preferable to distributed transactions across a database and a broker.
Diagram as text
This is the source of the diagram, in the ArchBoard diagram DSL. Paste it into Tools, Diagram from text to rebuild or change it.
title "Transactional outbox"
direction LR
service app "Order service" -> db postgres "Orders and outbox"
orders-and-outbox -> worker relay "Outbox relay" -> topic kafka "Order events"
order-events -> worker c1 "Billing consumer"
order-events -> worker c2 "Shipping consumer"
c1 -> cache redis "Processed ids"