Day 14: Publish-Subscribe in System Design
Prabhat
Sep 4, 20264 min read8 views
Publish-Subscribe: One Event, Many Independent Workflows
Learning outcome: By the end of Day 14, you will be able to explain how a publisher sends one event to a topic, why separate subscriptions enable fan-out, and which delivery trade-offs subscribers must handle.
This lesson is part of Korshub's System Design in 30 Days series.
Advertisement
The mental model: one announcement, multiple inboxes
Imagine an airport announces a gate change once. Several teams listen for the same announcement: the display system updates screens, the mobile app sends a notification, and operations records the change. The announcer does not call each team separately.
Publish-subscribe works the same way:
A publisher creates an event.
It publishes the event to a topic.
Independent subscriptions receive copies of that event.
Subscriber applications process the copies for different purposes.
The publisher knows the event contract and destination topic, but it does not need direct knowledge of every subscriber. That separation reduces direct coupling and makes it easier to add a new workflow later.
The Day 14 example: OrderCreated
Assume checkout finishes an order and publishes one OrderCreated event to an Orders topic. Three independent subscriptions are attached:
Subscription | Subscriber workflow | Result |
|---|---|---|
Inventory | Reserve stock | Inventory state is updated |
Notifications | Send confirmation | The customer receives an order message |
Analytics | Record the sale | Reporting receives the event |
The fan-out calculation is simple and exact:
1 published event x 3 independent subscriptions = 3 delivery copies
An independent check reaches the same total:
1 inventory copy + 1 notifications copy + 1 analytics copy = 3 copies
These are three deliveries of the same logical event, not three new orders.
Pub-sub is not the same as competing consumers
This distinction matters in interviews and production designs.
Design | Who receives a message? | Best fit |
|---|---|---|
One subscription with several consumers | Consumers share the work; each receives a subset | Scale one processing job |
Several independent subscriptions | Each subscription receives a copy | Run different workflows for the same event |
If inventory, notifications, and analytics all need every order event, give them separate subscriptions. If several inventory workers share one inventory subscription, those workers divide the inventory workload instead of each receiving every message.
Why teams use publish-subscribe
Loose coupling: Checkout does not need synchronous integrations with every downstream service.
Independent evolution: A subscriber can be added or changed without modifying the publisher's call graph.
Parallel workflows: Different consumers can process the same event for different outcomes.
Failure isolation: A slow subscriber does not have to block the publisher, although backlog, retention, and retry policies still require deliberate configuration.
The trade-offs you must say out loud
Publish-subscribe does not automatically guarantee exactly-once processing or global ordering. Delivery guarantees vary by broker and configuration. A subscriber may receive an event again after a retry, or later than another event.
Design subscribers to be idempotent: processing the same event twice should not create a second real-world effect. A practical event envelope often includes:
{
"eventId": "unique-event-identifier",
"eventType": "OrderCreated",
"occurredAt": "UTC-timestamp",
"orderId": "order-identifier",
"schemaVersion": 1
}
The subscriber can store or check eventId before applying a non-repeatable action. Schema versioning, access control, monitoring, dead-letter handling, and retention also belong in a production design.
Try this today
Add one more workflow to the Orders topic. Choose exactly one:
fraud detection;
product recommendations; or
shipping preparation.
Then answer three questions:
Does the workflow need every
OrderCreatedevent or only a filtered subset?What key will make processing idempotent?
What should happen after repeated failures?
Completed example: fraud detection subscriber
Subscription:
fraud-order-createdFilter: high-risk payment or account attributes, when the broker supports subscription filtering
Idempotency key:
eventIdProcessing: evaluate the order and emit a separate
FraudReviewRequestedevent when manual review is requiredFailure policy: retry transient errors, then route repeatedly failing messages to a dead-letter destination for investigation
Monitoring: alert on oldest unprocessed message age, delivery failures, and dead-letter volume
Checkout remains responsible for publishing a valid order event. The fraud workflow owns its own subscription and failure handling.
Common mistakes
Using one shared subscription for unrelated workflows. Competing consumers split messages; they do not all receive every event.
Assuming exactly-once business effects. Broker delivery and application-side processing are different guarantees.
Ignoring event contracts. Renaming or removing fields can break subscribers the publisher does not know about.
Treating pub-sub as instant. It is asynchronous; design for delay, backlog, and eventual processing.
Publishing sensitive data broadly. Give topics and subscriptions least-privilege access and include only necessary fields.
Knowledge check
1. Why use separate subscriptions for inventory and analytics?
Because both workflows need their own copy of each order event and should process independently.
2. If several workers consume from one inventory subscription, do all of them receive every message?
No. They normally share that subscription's work; each message is handled by one worker at a time, subject to redelivery behavior.
3. Why should a subscriber be idempotent?
Because retries or redelivery can cause the same logical event to be processed more than once.
Continue learning with Korshub
Use the complete microservices and event-driven architecture course to go deeper into event contracts, brokers, retries, and production workflows.
Series navigation
Previous: Day 13 - Message Queues
Roadmap: System Design in 30 Days