Event-driven architecture
Publish facts, not requests: consumers come and go freely, but the event's fields and order become the contract.
Predict first
Before you read: predict
ExamHall's submit handler stores each exam, and grading, analytics, the proctor dashboard and notifications react to every submission. A new certificate team wants its service to react too.
Which design lets that team ship by adding only its own files, with no other team's file changed?
The 30-second version
A command asks one service to act; an event announces a fact. Publish facts, and producers stop knowing their consumers: a new reaction is a new subscriber, with no producer edit. The coupling moves into the event's fields and into ordering assumptions, so change schemas additively, write them down, enforce order in the consumer, and trace with correlation ids.
Publish facts, not requests: consumers come and go freely, but the event's fields and order become the contract.
How it works
Step 1 of 12
Analogy: A local newspaper's births column
A family places one notice, "Lily, born 3 May", and never learns who reads it.
| In the births column | In the system |
|---|---|
| a notice of something that happened | an event in the past tense (step 2) |
| the family never learns who reads it | the producer knows no consumer (step 3) |
| a new reader buys the paper; the family does nothing | a new subscriber, no producer edit (step 3) |
| "please send gifts to…" printed as a notice | a command dressed as an event (step 4) |
| readers clip the date in the paper's set format | consumers depend on the fields (step 6) |
| births and weddings come from different desks, each on its own schedule | separate topics, each delivered on its own (step 9) |
Breaks down when: a reader who missed an issue cannot get it back, while a durable subscription keeps its messages until its consumer returns.
Contrasting case: phoning each relative in turn is a list of calls: a new relative means a new call, and one engaged line holds up the rest.
In real terms: the producer stops listing its consumers; the event's shape becomes what they share.
Examples, run for real
4.1 ExamHall EXH-3960: the submit handler that called everyone
ExamHall's submit handler called grading, analytics, notifications and the proctor dashboard in turn. Notifications failed on one of 40 submissions.
4.1 before: the submit handler calls grading, analytics, notifications, then the proctor dashboard · notifications failed on 1 submission: that candidate got an error for a stored exam (40 stored, 1 error), and the dashboard missed it (39 of 40) · adding a certificate reaction edits submit/handler.js
4.1 MR !4260: the handler publishes ExamSubmitted; each service subscribes · errors shown 0 · dashboard 40 of 40 · the failed notification waits for redelivery (1 message) · adding a certificate reaction edits no file outside the certificate team
MR !4260 publishes ExamSubmitted. The failure stays inside notifications, and the next reaction ships without touching the handler (steps 2, 3).
4.2 Media streaming: thin events and a late subscriber
A streaming service publishes VideoPublished to four subscribers; recommendations subscribes later.
4.2 media streaming: 100 thin VideoPublished events (an id only) x 4 subscribers = 400 calls back to the catalog · recommendations subscribes later: its handler runs 100 times · 100 events carrying title and duration: 0 calls back
An id-only event makes each subscriber fetch the video; events that carry the fields cause no fetches (step 10).
Try it
Answer first, then check. Nothing is saved.
Question 1 of 6
A streaming service's VideoPublished event carries durationSec. Three consumers read it: the player's progress bar, recommendations and per-minute billing. The team will rename it to durationMs. Its rule: the old field is removed only after a test has shown that no consumer needs it, and a consumer must never receive an event without the field it reads.
In what order does the team make the four changes?
Your order
- 1empty
- 2empty
- 3empty
- 4empty
Tap the lines in the order you expect.
Question 2 of 6
A streaming service's upload service needs the catalog service to put each transcoded video live. The catalog may refuse a video whose rights are not cleared, and the creator's upload page must show that refusal. Followers are told about each new live video by a service subscribed to VideoPublished.
Which design meets both needs?
Question 3 of 6
Five services consume MessageSent in a chat app, and two of them publish events of their own that two more services consume. A user's message was pushed twice to one phone. The interviewer asks how you would find every handler run that one message caused, and nothing else.
Which search finds them?
Question 4 of 6
A podcast app's catalog publishes EpisodePublished, which carries episodeId and title. Three services subscribe: search indexes each episode's title, the transcript service needs each episode's audio URL, and analytics counts episodes by episodeId. The catalog publishes 50 episodes; then its read API goes down, before any subscriber has handled them.
Which services finish all 50 while the API is down?
Question 5 of 6
A payments app's ledger publishes PaymentCaptured, and its refunds service publishes PaymentRefunded, on separate topics. The statement service keeps one status row per payment. A payment is captured, then refunded a second later, and the refund event is delivered first.
Which rule leaves the statement showing it refunded?
Question 6 of 6
A ticket site's OrderPlaced event carried seats: ['A1', 'A2']. The orders team changes it to seats: [{ id: 'A1', price: 40 }, { id: 'A2', price: 40 }], and the producer's own tests pass. The email service, a consumer, builds a line with this code:
What does the next confirmation email say?
function emailLine(event) { return 'Seats: ' + event.seats.join(', ');}Go deeper
Pro tips
- Before choosing an id-only event, count the calls back.
When: a design round, when you propose events between services and the interviewer asks what each consumer needs (step 10). Verify:
Status: RAN.tip 2,000 videos an hour x 5 subscribers that each call the catalog back = 10,000 catalog reads an hour that a fuller event would not cause
Source
quote-check.mjs finds every passage below verbatim in its saved text. Valid as of 2026-10-13.
- Martin Fowler, What do you mean by "Event-Driven"?: https://martinfowler.com/articles/201701-event-driven.html (
fowler-event-driven.txt). The row's first source. Quoted: "A key element of event notification is that the source system doesn't really care much about the response."; "it can be hard to see such a flow as it's not explicit in any program text"; "an event is used as a passive-aggressive command"; "the source system expects the recipient to carry out an action, and ought to use a command message to show that intention"; "The receiver knows something has changed, may get some minimal information on the nature of the change, but then issues a request back to the sender to decide what to do next."; "they don't need to contact the source system in order to do further work". - AsyncAPI Initiative, AsyncAPI Specification 3.0.0: https://www.asyncapi.com/docs/reference/specification/v3.0.0, saved from https://raw.githubusercontent.com/asyncapi/spec/v3.0.0/spec/asyncapi.md (
asyncapi-3.0.0.txt). The row's second source. Quoted: "Since a message is a generic mechanism, it can support multiple interaction patterns such as event, command, request, or response."; "Definition of the message payload."; "Definition of the correlation ID used for message tracing or matching."; "An object that specifies an identifier at design time that can used for message tracing and correlation." Supports steps 1, 8 and 11.
Related lessons
Checked against the tools and docs as of 2026-10-13.