DEV Community

Cover image for Back to Code | Ep 13: Event-Driven Architecture — Kafka and the Async World
Mehmet TURAÇ
Mehmet TURAÇ

Posted on

Back to Code | Ep 13: Event-Driven Architecture — Kafka and the Async World

The 15-week technical battle of LogiFlow — a company waking up from the illusion created by artificial intelligence and returning to real engineering.

The Story

When the "Invoice" service crashed, the "Routing" service also went down — because AI had connected them with synchronous HTTP (REST). Cascade Failure.

It was 2 AM when the pager went off. The invoice service had run out of memory — a memory leak in a PDF generation library. Within seconds, the routing service started timing out. Then the tracking service. Then the customer portal. One service's failure had cascaded through the entire system like dominoes.

"Why does the routing service care if invoicing is down?" Defne asked, already knowing the answer.
"Because AI made routing call invoicing synchronously after every route calculation," Emre admitted.

Technical Autopsy: Event-Driven Architecture

// Routing service (Producer)
await kafka.send({
  topic: 'routing.events',
  messages: [{
    key: truckId,
    value: JSON.stringify({
      type: 'RouteCalculated',
      truckId,
      eta,
      timestamp: Date.now()
    })
  }]
});

// Invoice service (Consumer) — Runs independently
consumer.run({
  eachMessage: async ({ message }) => {
    const event = JSON.parse(message.value);
    if (event.type === 'RouteCalculated') {
      await generateInvoice(event);
    }
  }
});
Enter fullscreen mode Exit fullscreen mode

Microservices should talk through Domain Events, not HTTP.

When the invoice service goes down now, the routing service doesn't notice. The events queue up in Kafka. When invoicing recovers, it processes the backlog. No cascade. No domino effect. No 2 AM pages.

Sync vs Async

Synchronous (HTTP) Asynchronous (Events)
Caller waits for response Fire and forget
Failure cascades Failure is isolated
Tight coupling Loose coupling
Easy to reason about Requires event schema design
Simple for 2 services Essential for 10+ services

Lessons from Episode 13

1. Loose Coupling: Services should not wait for each other.

2. Domain Events: 'RouteCalculated', 'InvoiceGenerated' — communicate through events.

3. Dead Letter Queue: Failed messages should not be lost — they should wait in a separate queue for investigation and replay.


This is Episode 13 of the "Back to Code" series. Next up: Episode 14 — Technical Debt Credit Score.

Series: back.to.code · 2026

Top comments (0)