Requirements checklist
□ Delivery guarantee — raise it unprompted: at-most-once (fire-and-forget, loss on failure) vs at-least-once (acked, redelivered, duplicates possible) — per subscriber, consequence owned aloud. Never asking is the round's biggest gap. □ Ordering: per-topic publish order to each subscriber; NO promise across topics □ Shape: in-process library, topics created on first use, nothing durable □ Threading: publish from any thread; callbacks on the broker's delivery machinery, never the publisher's thread □ Slow subscribers: bounded queue per subscription (capacity in config); full -> oldest dropped □ Out of scope: wildcards, topic filters, priorities
The core model
The claim PUBLISH NEVER RUNS SUBSCRIBER CODE —
publish appends to each subscription's queue
and returns; per-subscription workers deliver
Broker topic registry, created on first use
Topic publish lock covering seq assignment + fan-out
(the per-topic ordering point);
copy-on-write subscription list
Subscription OWNS queue (bounded, drop-oldest, drop counter),
worker, mode, pending/ack state
Ordering one queue + one worker per subscription = FIFO
end to end; nothing shared across topics
Subscribe race publish delivers to a list snapshot; new
subscriber cleanly misses the in-flight message
Unsubscribe remove from list first (no new enqueues), then
stop worker at a message boundary
Worker catch at-least-once -> re-enqueue (duplicates possible)
at-most-once -> loss, as contracted
Principles demonstrated (name them at the decision)
- Cohesion as isolation — the Subscription owns everything its delivery needs (queue, worker, mode), so subscribers cannot interfere and unsubscribe tears down one object.
- Designing to the contract — ordering costs exactly one critical section per topic, placed where the promise requires it; the promises not made (cross-topic order) are the parallelism kept.
- Invariant by construction — per-subscriber FIFO holds because one worker drains one queue; it isn't checked, it can't be violated.
- Named concurrency decisions — what the publish lock covers, and copy-on-write for the subscribe-during-publish race, stated rather than assumed.
Complexity facts
publish O(s) O(1)-enqueues under the topic lock — cheap
fan-out, no callbacks or I/O inside the lock
delivery O(1) per message per subscriber, on its own worker
memory bounded: sum of queue capacities + pending (ALO)
the caveat the per-topic lock serializes that topic's
publishers — the price of the order promise,
paid only by hot topics
What earns points, per report dimension
- Requirements & interface — raised the delivery-guarantee question unprompted and owned the chosen mode's consequence; pinned ordering scope and threading before designing.
- Core design & invariants — the publish-never-runs-subscriber-code claim stated as the design's center; one-queue-one-worker as the ordering mechanism; the subscribe race named with the boundary message's fate.
- Extension probe — price the promise the follow-up touches (order vs parallelism, acks vs memory) and land it on the Subscription/Topic seams.
- Complexity honesty — what the topic lock serializes and why that's acceptable; memory bounded by construction.
- Communication — lock coverage narrated while writing it; rejected designs (callbacks in publish, shared topic queue, global pool) named with reasons.
Ready? Sit the live mock → — the interviewer will run a twist this chapter deliberately hasn't shown you.