Part 7: Phase 2 — Dual-Write: Dapr PubSub + Conflict Resolution

In Phase 1, both systems existed but only one wrote data: Magento. In Phase 2, both systems write data simultaneously. This is the most technically complex phase — and the one where most migrations introduce data corruption if they don’t have an explicit conflict resolution strategy. Answer-first: Phase 2 uses event-driven dual-write — not raw database dual-write. Microservices write to their PostgreSQL first, then publish a domain event to Dapr PubSub. The magento-sync-adapter service subscribes to those events and writes back to Magento. Conflicts (both systems update the same record concurrently) are resolved by a 5-policy matrix that differs by data type: timestamp-based for customer profiles, microservices-wins for order status and stock levels, and summation reconciliation for coupon usage counts. ...

May 20, 2026 · 8 min · Lê Tuấn Anh

Part 9: Transactional Outbox & Saga for Guaranteed Delivery

When a customer places an order on the Composable Commerce Platform, seven events need to happen in sequence across four independent services: Order created → Payment authorized → Stock reserved → Fulfillment triggered → Notification sent → Loyalty points awarded → Shipping label generated. Any of these can fail. The network can fail. The database can fail. A third-party payment gateway can time out. Without a reliability mechanism, a 2% failure rate on any step means 2% of all orders are stuck in an inconsistent state, requiring manual intervention. ...

June 3, 2026 · 11 min · Lê Tuấn Anh

Kafka Worker Pool in Go — Backpressure & Exactly-Once

Prerequisite: Part 5 of the System Design Masterclass. Read Part 4: Database Scaling to understand the storage tier that persisted events are written to. Answer-first: Event-Driven Architecture decouples services through asynchronous communication via a durable message log. In Go, goroutines and buffered channels implement natural backpressure — when consumers fall behind producers, the channel fills up and blocks the producer, throttling the ingest rate automatically. Kafka vs RabbitMQ — When to Use Each? Answer-first: Kafka is a distributed commit log — messages are retained indefinitely, consumers manage their own offsets, and replay is possible. RabbitMQ is a message broker — messages are deleted after acknowledgment, the broker handles routing complexity, push-based delivery. They solve different problems. ...

June 18, 2026 · 8 min · Lê Tuấn Anh

Mastering Event-Driven Architecture with Dapr Pub/Sub

Answer-first: Build resilient event-driven microservices by using Dapr’s Pub/Sub APIs to decouple message transport. Ensuring eventual consistency requires implementing the Transactional Outbox pattern on writes, utilizing dead-letter queues (DLQs) for failed runs, and designing idempotent message handlers. What You’ll Learn That AI Won’t Tell You How to configure dead-letter queues in Dapr to handle poison messages. Designing idempotent message handlers that process duplicate events safely. In my previous post, we explored how abandoning monolithic architecture in favor of strict Domain-Driven Design (DDD) bounded contexts allowed an e-commerce platform to scale beyond 10,000+ orders per day. However, splitting one big database into 20+ isolated Postgres databases introduces a terrifying new problem: How do we maintain data consistency across disconnected services? ...

April 12, 2026 · 17 min · Lê Tuấn Anh