skip to content

You're designing a system where an OrderPlaced event needs to independently trigger inventory update, email notification, and analytics logging at different paces, while a separate CapturePayment step must be processed exactly once by exactly one worker with strict, ordered handling per account. Would you use a pub-sub topic or a point-to-point queue for each, and how would you combine them?

level: principalimportance: should knowfreq 55%

answer

  1. fan-out=pub-sub topic, independent groups
  2. exactly-once-per-key=queue or partitioned topic
  3. account-ID partition key for ordering
  4. fanout topic to per-service queues
  5. don't force one pattern to do both jobs

basics

~20 s

For OrderPlaced, use pub-sub - every interested service (inventory, email, analytics) needs its own full copy at its own speed. For CapturePayment, use a point-to-point queue so only one worker handles each payment exactly once, with per-account ordering.

solid answer

~50 s

OrderPlaced is a broadcast fact that multiple unrelated services need to react to independently - the textbook pub-sub case: publish to a topic so inventory, email, and analytics each get their own subscription, consuming at their own pace with zero coupling between them. CapturePayment is a unit of work that must be done exactly once per payment, with per-account ordering so a refund never races ahead of its preceding charge - that's the point-to-point (or partitioned) case: route it through a queue, or a partitioned topic keyed by account ID, consumed by a pool of workers using competing-consumers semantics within each account's partition. In practice these compose in the same architecture: a broker like Kafka gives both via topics/partitions and consumer groups, or you can mix technologies - a fanout topic feeding separate queues per downstream service for OrderPlaced, and a FIFO queue with per-account message group IDs for CapturePayment.

go deeper

for a junior

Should be able to identify, at a basic level, that OrderPlaced sounds like notifying several different things (pub-sub) and CapturePayment sounds like doing this job once (queue).

for a middle

Should articulate why fan-out via three manual queue sends from the order service is worse than a topic (coupling, harder to extend), and name a concrete ordering mechanism (partition key / message group ID) for CapturePayment.

for a senior

Should design the combined architecture concretely (e.g., fanout-to-queues plus a FIFO/partitioned queue for payments) and identify the added observability burden of running two patterns side by side.

for a principal

Should anticipate hot-partition/hot-key risk at scale, plan partition-count sizing and repartitioning strategy, and make the call on whether to standardize on one broker technology for both, with consumer groups and partition keys, versus deliberately mixing technologies suited to each pattern.

## Where the choice stops being academic This kind of scenario is where the pub-sub-vs-queuing decision stops being academic and becomes an actual architecture decision with real consequences, because the two workflows described have genuinely different cardinality and ordering requirements, and picking the wrong messaging primitive for either one creates real production pain. ## OrderPlaced is a fan-out requirement **Analyzing OrderPlaced first:** the defining characteristic is that three independent, mutually-unaware downstream services (inventory, email, analytics) all need to react to the same fact, each at its own pace, with no coordination between them. - This is a pure **fan-out** requirement: the publisher (the order service) should not need to know or care who's listening, and a fourth interested party, say a future fraud-scoring service, should be addable later with zero changes to the order service. - This uniquely matches pub-sub: publish OrderPlaced to a topic, and let each downstream service maintain its own independent subscription. Inventory can process instantly; email can be slower and even batch; analytics can lag by hours during a backfill, and none of that affects the others. - If this were instead implemented as three separate point-to-point queues manually filled by the order service calling three different send calls, similar fan-out behavior would result, but the order service would be coupled to knowing about every downstream consumer explicitly — adding a fourth consumer means changing the order service's code, defeating the loose-coupling benefit pub-sub is meant to provide. A topic with a fanout mechanism (native Kafka topic plus consumer groups, or a fanout exchange to per-subscriber queues) gets fan-out without that coupling. ## CapturePayment is work distribution **Analyzing CapturePayment:** the defining characteristic here is the opposite — this must happen exactly once, by exactly one worker, with correctness on ordering per account so a payment capture and any related refund/adjustment for the same account are processed in the sequence they actually occurred. - This is a point-to-point **work-distribution** problem, not a fan-out problem: multiple workers should exist purely for horizontal scaling of throughput, and each capture should be picked up and completed by exactly one of them. - If ordering matters per account, avoiding the classic bug of a refund processed before its preceding charge, plain unordered competing-consumers isn't enough — per-key ordering is needed, achieved by **partitioning**: route by account ID so all of one account's payment events land on the same partition/consumer, while still parallelizing across different accounts. This is precisely what FIFO queues with a message group ID, or Kafka partitions keyed by account ID, are built for. ## Why not force one model onto both jobs Keep them as two separate patterns rather than forcing one model to do both jobs: - Forcing CapturePayment through a naive pub-sub topic with multiple subscribers would mean every subscriber processes every capture, clearly wrong, since exactly one worker per payment is wanted, not N redundant charges. - Forcing OrderPlaced through a single point-to-point queue would mean only one of inventory/email/analytics gets each event, whichever worker wins the race, silently dropping two-thirds of the fan-out actually needed, a very common and dangerous misconfiguration bug. ## Putting both on one broker How they combine architecturally: at the messaging-technology level, two different products aren't strictly required — the right pattern needs to be applied per workflow, possibly on the same broker. | | With Kafka | With a fanout-plus-queue style toolkit | |---|---|---| | **OrderPlaced** | goes to a topic consumed by three separate consumer groups (inventory-group, email-group, analytics-group) — each group gets the full stream independently (pub-sub across groups), while within each group multiple instances can still load-balance via partitions if that group's own throughput needs it | with a fanout-plus-queue style toolkit, publishes to a fanout topic feeding three separate queues, one per downstream service, each independently drained by that service's own worker pool | | **CapturePayment** | goes to a different topic partitioned by account ID, consumed by a single consumer group (payment-workers) whose instances split partitions among themselves — competing-consumers within the group, ordering preserved per account via partition-per-key | goes to a FIFO queue with account ID as the message group ID, consumed by a pool of payment workers | ## Running both side by side Trade-offs and failure modes to watch for at this scale: - **Mixing patterns adds operational surface area.** Lag/backlog per subscription now needs monitoring for the pub-sub side, and queue depth plus DLQ health for the point-to-point side, doubling the observability surface compared to a single uniform pattern. - **Under-provisioning partition count.** A frequent principal-level mistake is under-provisioning partition count for the payment topic relative to account cardinality and volume, causing hot-partition bottlenecks once a large merchant's account concentrates disproportionate traffic on one partition — this needs sizing and periodic revisiting as traffic grows, since repartitioning an existing keyed topic is disruptive.

  • What would go wrong if you used a single plain (non-FIFO, non-partitioned) queue for CapturePayment with multiple competing consumers?
    You'd get correct at-least-once, exactly-once-per-message processing (each capture handled once) but no ordering guarantee across messages, so a refund for account X could be processed by a fast consumer before the preceding charge for account X, handled by a slower consumer, completes - producing incorrect balance calculations or false insufficient-funds errors.
  • If the analytics consumer for OrderPlaced falls behind by several hours during a backfill, does that affect inventory or email processing?
    No - because pub-sub gives each subscription its own independent cursor/backlog, analytics lagging has zero effect on inventory's or email's consumption rate or correctness; this isolation is exactly the benefit of using separate subscriptions rather than one shared queue for all three.
  • How would you decide how many partitions to allocate to the CapturePayment topic?
    Size for expected peak per-partition throughput given the account-ID key distribution, over-provision moderately since increasing partition count later can disrupt existing key-to-partition assignment, and watch for skew from very high-volume accounts that might need dedicated handling, such as a separate high-volume merchant partition or key-splitting, to avoid a hot-partition bottleneck.

OrderPlaced is like a company-wide announcement email sent to three separate departments who each act on it independently and at their own pace. CapturePayment is like a single ticket dropped into one specific teller's queue at a bank branch dedicated to that customer's account, so every transaction for that customer is handled by the same teller in the order it arrived.

saying these in an interview costs you the question

  • Proposes the same messaging pattern for both workflows without justifying the difference
  • Doesn't recognize CapturePayment needs per-account ordering, not just exactly-once delivery
  • Assumes pub-sub subscribers must all keep pace with each other
  • Can't explain the coupling cost of hardcoding three separate queue sends from the order service instead of using a topic
  • Ignores partition/key sizing and hot-key risk when proposing a partitioned solution

context