Transactional Outbox Pattern
TL;DR
The Outbox pattern atomically saves domain events to an 'outbox' DB table in the same transaction as business data — a relay then publishes to the message broker, preventing lost events.
Explanation
Problem: update DB and publish message — if broker publish fails after DB commit, event is lost. Solution: write to an 'outbox' table in the same DB transaction as the domain data. A separate relay process reads the outbox and publishes to the broker, deleting rows after confirmed publish. This achieves atomic write-to-DB and guaranteed eventual publish. CDC (Change Data Capture): use Debezium to read DB transaction log and publish to Kafka — no outbox table needed. Polling relay: simpler, slight delay. Event store: Kafka as the source of truth (event sourcing). Implementations: Symfony Messenger Doctrine transport, Transactionally Outbox libraries.
Common Misconception
✗ A DB transaction plus broker publish are atomic — they're not. The broker publish can fail after the DB commits, losing the event silently.
Why It Matters
Outbox pattern closes the dual-write consistency gap — the most common source of lost events in event-driven microservices.
Common Mistakes
- Dual-write without outbox — publish to broker then DB commit (or vice versa) can leave them inconsistent.
- Not cleaning up old outbox rows — table grows unboundedly.
- Relay not idempotent — duplicate publish on relay restart.
Code Examples
✗ Vulnerable
// Dual-write — inconsistent on failure:
$db->beginTransaction();
$db->insert('orders', $orderData);
$db->commit();
$broker->publish('order.created', $event); // Fails? Event lost.
✓ Fixed
// Outbox pattern:
$db->beginTransaction();
$db->insert('orders', $orderData);
$db->insert('outbox', [
'topic' => 'order.created',
'payload' => json_encode($event),
'created_at' => now(),
]);
$db->commit();
// Relay process reads outbox and publishes asynchronously
// Idempotent: broker publish + delete outbox row
Tags
🤝 Adopt this term
£79/year · your link shown here
Added
23 Mar 2026
Views
33
🤖 AI Guestbook educational data only
|
|
Last 30 days
Agents 1
No pings yesterday
Amazonbot 9
Perplexity 9
Unknown AI 3
SEMrush 3
Ahrefs 2
ChatGPT 2
Google 1
Also referenced
How they use it
crawler 27
crawler_json 1
pre-tracking 1
Related categories
⚡
DEV INTEL
Tools & Severity
🟠 High
⚙ Fix effort: High
⚡ Quick Fix
Add outbox table to every service that publishes events. Write to outbox in same transaction as domain data. Build idempotent relay process. Delete rows after confirmed publish.
📦 Applies To
web
cli
queue-worker
Symfony Messenger
🔗 Prerequisites
🔍 Detection Hints
outbox|publish.*commit|commit.*publish
Auto-detectable:
✗ No
⚠ Related Problems
🤖 AI Agent
Confidence: Low
False Positives: High
✗ Manual fix
Fix: High
Context: File
Tests: Update