Outbox vs CDC: A Decision Matrix for Event‑Driven Microservices
Problem: “When does my data get out of sync with my events?”
📦 🛠️ Choose the right event source: Outbox is simple but can lag, Transactional Outbox guarantees atomicity, CDC is real‑time but complex.
🎯 System Scenario & Requirements
System Goal
📦 🛠️ Choose the right event source: Outbox is simple but can lag, Transactional Outbox guarantees atomicity, CDC is real‑time but complex.
Actors & Components
- Database
- Event Worker / CDC Agent
- Message Broker (Kafka)
- Order Service
- Outbox Table
- CDC Agent
- Outbox Worker
- Kafka Topic
Functional Requirements
- TLDR: 📦 🛠️ Choose the right event source: Outbox is simple but can lag, Transactional Outbox guarantees atomicity, CDC is real‑time but complex.
- In a microservice, you often write to a database and want to publish an event to a message broker.
- If the write succeeds but the publish fails (network glitch, broker down), you end up with a data‑event split : the database reflects the change, but downstream services never see it.
Constraints & Assumptions
- Constraints are derived from the rebuilt scenario stages.
⚡ Execution Stages & Decision Trace
Stage 1 — The Three Strategies
Apply event-driven-architecture to The Three Strategies.
The system executes the mechanisms described for “The Three Strategies”.
Deep Dive
Scenario context
📦 🛠️ Choose the right event source: Outbox is simple but can lag, Transactional Outbox guarantees atomicity, CDC is real‑time but complex. In a microservice, you often write to a database and want to publish an event to a message broker. If the write succeeds but the publish fails (network glitch, broker down), you end up with a data‑event split: the database reflects the change, but downstream services never…
This walkthrough focuses on Problem: “When does my data get out of sync with my events?”.
Before making a design choice, clarify:
- In a microservice, you often write to a database and want to publish an event to a message broker.
- If the write succeeds but the publish fails (network glitch, broker down), you end up with a data‑event split : the database reflects the change, but downstream services never see it.
- This inconsistency can cascade, leading to stale caches, incorrect analytics, or failed business flows.
Concepts in play: event-driven-architecture, transaction-isolation-distributed-acid, message-queues, consistency-replication
Stage 1 — The Three Strategies
Observable outcome: You can explain how “The Three Strategies” changes the architecture or implementation path.
Stage 2 — Decision Matrix: When to Pick Each
Observable outcome: You can explain how “Decision Matrix: When to Pick Each” changes the architecture or implementation path.
Stage 3 — Quick Implementation Sketch (Transactional Outbox with Spring Data JPA)
- A lightweight worker polls outbox events and publishes to Kafka, then marks the row as sent or deletes it.
- The key is that the DB transaction guarantees the order write and the outbox row are committed together.
@Entity
@Table(name = "orders")
class Order {
@Id @GeneratedValue Long id;
String status;
// …
}
@Entity
@Table(name = "outbox_events")
class OutboxEvent {
@Id @GeneratedValue Long id;
String aggregateType;
Long aggregateId;
String payload; // JSON
Instant createdAt;
}
@Service
class OrderService {
@Transactional
void placeOrder(Order order) {
orderRepository.save(order); // domain write
// outbox write in same tx
OutboxEvent e = new OutboxEvent();
e.setAggregateType("Order");
e.setAggregateId(order.getId());
e.setPayload("{\"orderId\":" + order.getId() + "}");
e.setCreatedAt(Instant.now());
outboxRepository.save(e);
}
}
Observable outcome: The key is that the DB transaction guarantees the order write and the outbox row are committed together.
Stage 4 — Architecture Kit Diagram
- { "version": 1, "title": "Event Source Strategies", "description": "Comparing Outbox, Transactional Outbox, and CDC flows", "view": "data-flow", "pattern": "reactive-pull", "direction": "LR", "groups": [ { "id": "db", "…
Observable outcome: { "version": 1, "title": "Event Source Strategies", "description": "Comparing Outbox, Transactional Outbox, and CDC flows", "view": "data-flow", "pattern": "reactive-pull", "direction": "LR", "groups": [ { "id": "db", "…
End-to-end outcome
After working through the stages, you should be able to explain:
- Transactional Outbox is the gold‑standard for strong consistency.
- Outbox is great for simpler, low‑latency needs.
Alternatives considered
The source focuses on one primary design. A second architecture is not compared, so no alternative is invented here.
Failure and degraded modes
The source does not isolate a separate failure mode. Limits that matter for the scenario are called out in the stage decisions above.
Key learnings
- Transactional Outbox is the gold‑standard for strong consistency.
- Outbox is great for simpler, low‑latency needs.
- Apply event-driven-architecture to The Three Strategies.
- Apply transaction-isolation-distributed-acid to Decision Matrix: When to Pick Each.
- A lightweight worker polls outbox events and publishes to Kafka, then marks the row as sent or deletes it.
