Event-Driven Microservices

Event-driven microservices that survive contact with production.

Most event-driven rewrites fail quietly — a consumer that isn't idempotent double-processes an order, an outbox that isn't transactional loses an event during a deploy, a retry storm takes down the very topic it was supposed to protect.

We design Spring Boot services on Kafka with the failure modes handled up front: transactional outbox for reliable publishing, idempotent consumers so retries are safe, dead-letter queues so a bad message doesn't block the topic, and backpressure so one slow consumer doesn't cascade.

01  In practice

What this looks like in practice

01

Kafka topic and partition design around your actual access patterns, not a generic tutorial layout.

02

Transactional outbox pattern so a DB write and an event publish either both happen or neither does.

03

Idempotent consumers keyed on business identity, not just message ID.

04

Dead-letter queues with a replay path your team can actually operate.

05

Schema Registry (Avro/Protobuf) so producers and consumers don't drift silently.

06

Load-tested throughput numbers before go-live, not after the first incident.

02  Deliverables

What you get

  • Architecture decision record
  • Topic and partition design document
  • Working outbox + consumer implementation
  • Dead-letter runbook
  • Load test results — latency and throughput at target volume
03  Proof

Event-driven, in production

Order-processing platform at scale — event-driven Spring Boot services on Kafka, 90% faster processing, in production for 2+ years for the same client. Read the case study →

04  FAQ

Event-driven microservices — frequently asked questions

Why do event-driven rewrites fail?
Usually quietly, and usually for one of three reasons. A consumer that is not idempotent double-processes an order when a retry fires. An outbox that is not transactional loses an event when a deploy interrupts it between the database write and the publish. Or a retry storm takes down the very topic it was meant to protect. None of these show up in a demo — they show up under production load, which is why we design for them up front rather than patching them in after the first incident.
What is the transactional outbox pattern, and why do we need it?
It solves the dual-write problem: when a service has to both write to its database and publish an event, those are two separate systems and there is no shared transaction across them. If the process dies in between, you get a database row with no event, or an event with no row. The outbox pattern writes the event into an outbox table inside the same database transaction as the business data, then a separate relay publishes it to Kafka. Either both happen or neither does.
How do you make consumers idempotent?
We key idempotency on business identity rather than message ID. A message ID only protects you against the same physical message being delivered twice; it does not help when the same logical event arrives via a different message after a replay or a producer retry. Keying on the business fact — this order, this state transition — means reprocessing is safe regardless of how the message got there.
Do we need a Schema Registry?
If more than one team produces or consumes on a topic, yes. Without a registry, producer and consumer expectations drift silently — a field is added or a type changes, and the failure surfaces as a deserialization error in production rather than a rejected build. With Avro or Protobuf in a registry, incompatible changes fail at publish time, which is where you want them.
Can you work with our existing Kafka setup?
Yes, and that is the more common engagement. We start with your current topics, consumers and failure modes rather than proposing a rebuild, identify where the reliability gaps actually are, and fix those. A full redesign is only worth it when the topic and partition layout is fundamentally mismatched to your access patterns.

Talk to an architect about your event system.

Tell us where your events are going missing, backing up or being processed twice — we'll map the fix.

Talk to an architect