Transactional Outbox: publishing events safely with a database change

Django Interview Q&A November 13, 2026 python

If I write to the database and then send to the broker, one of the two can fail.

python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# ======================================================================
# Q: How do you safely publish an event together with a database change? (the
# dual-write problem)
#
# If I write to the database and then send to the broker, one of the two can
# fail. Solution: Transactional Outbox. In the same transaction I write the
# order and a row in the outbox table. A relay (Celery beat, a separate worker,
# or CDC with Debezium) reads the outbox and publishes. Consumers are idempotent
# (an inbox table with processed event_ids).
# ======================================================================

with transaction.atomic():
    order = Order.objects.create(...)
    OutboxEvent.objects.create(
        event_type='order.placed', aggregate_id=order.id,
        payload={'order_id': order.id, 'total': str(order.total)})

# relay: every few seconds
for ev in OutboxEvent.objects.select_for_update(skip_locked=True)\
                             .filter(published_at=None)[:100]:
    broker.publish(ev.event_type, ev.payload, message_id=str(ev.id))
    ev.published_at = timezone.now(); ev.save(update_fields=['published_at'])