← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

Transactional Outbox Pattern

messaging Advanced

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

Added 23 Mar 2026
Views 33
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 1 ping T 0 pings F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 2 pings T 0 pings F 3 pings S 0 pings S 0 pings M 0 pings T 1 ping W 0 pings T 0 pings F 1 ping S 1 ping S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 1 ping S
No pings yesterday
Amazonbot 9 Perplexity 9 Unknown AI 3 SEMrush 3 Ahrefs 2 ChatGPT 2 Google 1
crawler 27 crawler_json 1 pre-tracking 1
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

✓ schema.org compliant