A team is deciding whether to make 'reserve seat' in a ticketing checkout flow synchronous or route it through a queue for a downstream consumer to process. What criteria should drive that choice, and what's a concrete case where routing it through a queue would be the wrong call?
answer
- precondition vs side effect
- scarce contended resource -> sync
- optimistic locking / unique constraint for reservation
- overselling as the failure mode
- async only for what doesn't gate the response
basics
~20 sIf the caller needs a real, immediate yes/no answer before its next step — like confirming a seat is available before charging a card — a queue is wrong, since the caller would move on before knowing the real answer.
solid answer
~50 sThe deciding question: does the caller need the result to make its own immediate next decision, or is this a side effect that can safely complete later? Seat reservation is a hard case for async — if 'reserve seat' just returns 'accepted', checkout can't know before charging the card whether the seat was really available, so two customers could both be charged for one seat. The right call is synchronous availability-checking/reservation (backed by a database constraint or lock ensuring only one reservation wins), with async used afterward for anything that doesn't gate the response — confirmation email, analytics, partner notifications. General rule: sync when the result is a hard precondition or strong consistency beats throughput smoothing; async when the work is a pure side effect or inherently bursty and the caller doesn't need to wait.
go deeper
Should be able to say, in plain terms, that some things need an answer right away (is the seat free?) while others can happen later (the confirmation email), without needing to name specific mechanisms.
Should identify seat reservation as needing a synchronous, correctness-critical check and know that a queue-based 'accepted' response can't tell the customer the real answer immediately.
Should propose concrete synchronous concurrency control (unique constraint, optimistic locking) and draw the line clearly between what stays sync and what moves async in the same flow.
Should reason about this as an architectural policy applied consistently across a system — how to identify precondition-vs-side-effect operations up front, how to scale the synchronous path itself under contention (sharding, admission control), and the business cost calculus (overselling risk vs infrastructure cost) that justifies the choice.
## The core criterion The core criterion is whether the caller needs the answer to decide what to do next, or whether the operation is a downstream **side effect** that the caller's own success doesn't logically depend on. This sounds simple but it's easy to get backwards, because async messaging's benefits — decoupling, buffering, horizontal scalability — are real and often make a team reach for a queue by default for anything that looks like background work. Seat reservation in a ticketing flow is exactly the case that exposes the flaw in that default: reserving a seat isn't a side effect of checkout, it's the **precondition** checkout depends on. If 'reserve seat' becomes 'publish a reservation-requested message and immediately return 202 Accepted,' the checkout flow has nothing true to tell the customer yet — it doesn't know if the seat is actually available, because the async consumer that will find out hasn't run. If checkout proceeds to charge the card optimistically on that 'accepted' response, you can end up charging a customer for a seat that turns out to be sold out, requiring a refund and an apology — a strictly worse failure mode than a synchronous check that just says 'sold out' immediately, before any payment is attempted. ## Why it is an architecture question The reason this matters at the architecture level, not just as a one-off implementation detail, is that mixing up 'hard precondition' with 'side effect' tends to happen precisely when a system is under load — the exact moment a team is most tempted to async-ify something to relieve pressure, and the exact moment getting it wrong is most costly, because that's also when contention for a scarce resource (the last few seats) is highest and double-booking risk is greatest. The general decision criteria are: - **(1)** does the caller's own next action require this result to be correct, not just 'eventually correct'? If yes, it needs a synchronous answer, even if that synchronous path is itself backed by fast, well-indexed infrastructure rather than a slow legacy call. - **(2)** Is strong consistency more valuable here than throughput smoothing? Seat availability is a classic scarce, contended resource where two requests racing for the same unit of inventory need a definitive winner and loser resolved immediately (via a database unique constraint, an optimistic-locking version check, or a distributed lock), not two requests both told 'accepted, we'll figure it out.' - **(3)** Is the operation naturally low-latency and low enough volume that synchronous handling doesn't create the load or availability problems async messaging exists to solve? A single row-level database check-and-update is fast; a request that fans out to five other services is not, and is a better async candidate — for the parts of it that aren't gating the immediate response. ## What choosing sync costs The trade-off in choosing sync here is that you give up the elasticity async gives you — a synchronous seat-reservation path has to be provisioned to handle its own peak load directly (connection pools, database write throughput, contention handling under a ticket-drop stampede), rather than letting a queue smooth a burst. This is a real cost: high-demand ticket releases are notorious for exactly this kind of synchronous contention meltdown, and the honest answer is that sync-for-correctness doesn't remove the scaling problem, it just means the scaling problem has to be solved with different tools: - optimistic concurrency control, - sharding inventory by section/row so contention is spread across many rows instead of one hot counter, - queuing customers into a virtual waiting room before they even reach the reservation endpoint, - or bounded-concurrency admission control — rather than papering over it with 'accepted' responses that turn out to be wrong. ## The failure modes Failure modes when this is gotten wrong in production are specific: 1. **Overselling** (multiple customers shown 'confirmed' or allowed to pay for the same seat because the authoritative availability check happened asynchronously and too late relative to the payment step), 2. a **support/refund burden** that's expensive and reputationally costly compared to a clean synchronous rejection, 3. and a **customer trust hit** disproportionate to the technical cause. The inverse failure — making something synchronous that should have been async — shows up as the checkout API blocking on non-critical work (an email service, a loyalty microservice) and failing the whole checkout because a side effect was slow, which is the original motivating problem async messaging solves. ## Where it shows up A well-known real-world instance of getting this right is how high-demand ticketing platforms architect seat/inventory holds as a synchronous, strongly consistent operation — typically a short-lived reservation lock tied to the checkout session, enforced at the database or cache layer with atomic compare-and-set semantics — while everything downstream of a successful purchase (confirmation email, calendar invites, loyalty point accrual, analytics) is fanned out asynchronously, because none of that downstream work can retroactively un-sell a seat that's already been correctly, synchronously confirmed as sold.
- How would you keep seat reservation synchronous without it becoming a scaling bottleneck during a high-demand ticket drop?Use fine-grained contention control rather than one global lock — a unique constraint or optimistic-concurrency version check per seat row so contention is spread across many independent rows instead of a single hot counter, and admit customers into the reservation flow through a bounded-concurrency queue or virtual waiting room upstream so the synchronous path only ever sees a controlled, sustainable request rate rather than the full instantaneous demand spike.
- Is there a middle ground between fully synchronous and fully async for something like seat reservation?Yes — the reservation/availability check itself stays synchronous and authoritative (fast, contended, correctness-critical), while everything that depends on a successful reservation but doesn't need to complete before responding to the customer — confirmation email, loyalty accrual, partner notifications — is published async afterward. The key discipline is drawing that line precisely at 'what does the response the customer sees depend on,' not asyncifying the whole request because parts of it are slow.
- What's the actual cost, in production terms, of getting this wrong by async-ifying the reservation itself?Overselling: multiple customers can be told 'accepted' or even charged for the same seat before the async consumer resolves which one actually gets it, producing refunds, customer-trust damage, and manual support intervention — costs that are typically far higher than the infrastructure cost of handling the contention synchronously in the first place.
Like a bouncer checking a guest list at the door versus mailing out a party recap afterward: whether you're let in has to be answered right now, synchronously, before you do anything else (like handing over your coat) — the after-party photo email can take its time and doesn't need you standing there waiting for it.
saying these in an interview costs you the question
- Treats 'async is more scalable' as a universal rule that should apply to every operation
- Doesn't distinguish a precondition the caller needs from a side effect that can happen later
- Proposes making the whole checkout flow async including the availability check itself
- No concrete concurrency-control mechanism offered for the synchronous path (unique constraint, optimistic lock, etc.)
- Doesn't recognize overselling/double-booking as the concrete failure this choice risks