Event-Driven Architectures
Publish facts, subscribe to outcomes
EDA decouples producers from consumers via a bus: SNS/EventBridge, Event Grid, Pub/Sub. Producers publish facts; consumers subscribe. Delivery is at-least-once, so idempotency and retry/poison handling are contracts, not features.
What you will learn
- Model events as domain facts with schema + versioning
- Route events with filters rather than fan-out code
- Design idempotent consumers and poison-message handling
A producer publishes an event to a bus; the bus fans it to matching subscribers. Services stay decoupled: adding a consumer is a config change, not a code change in the producer.
What is this?
Bus types: SNS (topic, pub/sub), EventBridge (event bus + rules + targets/schedules), Azure Event Grid (topic + subscriptions + filters), Pub/Sub (topic + push/pull subscriptions). Event shape: envelope (metadata, source, detail-type) + detail incl. JSON schema + version. Routing: filter on source/type/attributes; dead-letter / DLQ per subscriber; retries (exponential, bounded). Delivery: at-least-once ⇒ duplicate possible ⇒ consumer idempotency (dedupe key). Ordering: generally not guaranteed cross-partition; SQS FIFO/Event Grid partial ordering differ. Pattern taxonomy: events, commands, queries; saga/outbox vs choreography.
Why do you need it?
- Decoupling lets teams ship consumers without touching (or coordinating with) producers.
- Bus provides buffering, retries, and fan-out — no bespoke scaling code per integration.
- Event audit trail doubles as a change log for downstream systems.
- Adding a cross-team consumer becomes a subscription + schema version, not a PR into a monolith.
Mental model
A radio station broadcasting, listeners tune in when they care
Event bus pub/sub
The station (producer) doesn't know its audience; each listener (consumer) subscribes, filters, and can join or leave without the station changing anything.
How it works
- Producer validates + publishes a versioned structured event.
- Bus applies subscriber filters and routes to matching targets.
- Each target tries delivery with retries; failures land in a DLQ.
- Consumers process; duplicates possible → consumer keying/idempotency.
- Consumers scale independently; back-pressure is per-queue.
Event flow.
Examples
Declarative routing idea (cloud-agnostic)
rule "order-events": event * source=orders type=order.* target analytics.sink() target notify.fanout()# consumers upgrade schema independentlytype order.created → v2: order-id, items[] (was: ids)Routing and filtering live in the bus config; consumers own their interpretation of the versioned schema.
In production
- Order pipeline: order.created → inventory, billing, search-index, analytics concurrently.
- Multi-service fan-in to one warehouse: all domain events → lake loader.
- Asynchronous notification flows: user.signup → welcome email + fraud check.
- Saga compensation via outbox: emit command events, orchestrator coordinates.
Best practices
- Emit facts (order.cancelled), not commands (sendEmailToUser).
- Monotonic scheMAS: add fields, rarely remove; version major changes explicitly.
- Make consumers idempotent: dedupe on event id or a deterministic business key.
- Give every subscriber its own DLQ and alert on DLQ depth > 0.
- Set sensible retry policies: exponential with jitter, bounded attempt count.
Common mistakes
- Treating the bus as a message queue; both exist, don't blur them.
- Synchronous fan-out in producer code instead of using filters.
- Consumers ignoring duplicates, then 'we charged twice' incidents.
- Tightly coupling schemas so every producer change is a consumer release too.
Debugging tips
- Inspect the bus's dead-letter queue first; most 'missing events' die there.
- Replay a single event from the bus (EventBridge replay, SNS/DLQ redrive).
- Spawns two identical schemas with different namespaces → filter typo case.
- Tracks event-id vs processing-id: dedupe collisions vs real drivers.
Interview checkpoint
Hands-on lab
- Publish one event to two consumers via a bus
- Configure filters and a DLQ
- Hardware-proof duplicate-safe processing with a dedupe key
Fan-Out with a Bus and Prove Idempotency
45 min · intermediate
Quick quiz
Default cloud event delivery is:
Adding a new consumer in EDA typically requires: