Write events to the DB in the same transaction as data — a worker reliably publishes them to Kafka.
The Outbox Pattern
# Problem: publish event AND save to DB atomically
# Without outbox: DB saves, Kafka publish fails -> lost event!
# With outbox: write to outbox table in same transaction
CREATE TABLE event_outbox (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
event_type VARCHAR(100),
payload JSONB,
created_at TIMESTAMP DEFAULT NOW(),
published BOOLEAN DEFAULT FALSE
);
-- Application code (atomic)
BEGIN;
INSERT INTO orders (user_id,total) VALUES (1,99.99);
INSERT INTO event_outbox (event_type,payload)
VALUES ('OrderPlaced','{"order_id":1,"total":99.99}');
COMMIT;
-- Worker publishes and marks done
rows = db.query('SELECT * FROM event_outbox WHERE NOT published')
for row in rows:
kafka.publish(row.event_type, row.payload)
db.execute('UPDATE event_outbox SET published=TRUE WHERE id=%s',[row.id])