Lowest-Price Book Aggregator Fanning Out to Hundreds of Async Bookstores
Company: Databricks
Role: Software Engineer
Category: System Design
Difficulty: medium
Interview Round: Onsite
You run a middleman service for buying books. A customer submits an ISBN, a bid price and a payment method. The system fans out a price query to several hundred partner bookstores and finds the lowest price. If the lowest price is at or below the bid, the system places the order right away; otherwise it returns the lowest price to the customer. If no store has the book in stock, the system notifies the customer.
The interviewer sets two premises: the downstream bookstores are asynchronous, and the volume of external calls is large. Design the system, then go deep on the areas below.
### Clarifying Questions
- What does "asynchronous" mean for a store: we send a request and the quote arrives later through a callback or message, or we simply call the store without blocking?
- Does the customer wait on an open request for the outcome, or learn it later through a notification?
- Is a store's quoted price binding when we place the order, or can the price change between quote and order?
- When the lowest price is above the bid, does the request end there, or can the customer accept the returned price and proceed?
- What does the payment step look like: an authorization hold followed by a capture, or a single immediate charge?
### Part 1 — Core flow
Describe the APIs, the main components, and the lifecycle of one purchase request, from submission to each of its outcomes: order placed, lowest price returned, or out of stock.
```hint A request is a long-lived object
With several hundred asynchronous replies per request, think about where the in-progress state of one request lives, and what closes it.
```
#### What This Part Should Cover
- The client-facing API, and how the result reaches the customer
- Fan-out and aggregation mechanics for asynchronous replies
- Persistent state for a purchase request, and its transitions
### Part 2 — Downstream fault tolerance
Several hundred stores are too many to wait for, and some time out or are down. How do you aggregate partial results, and should you use a circuit breaker?
```hint When is "enough" enough?
Decide what event ends the waiting for a request, and what that means for the correctness of "lowest price" and "out of stock".
```
#### What This Part Should Cover
- Deadlines, and the rule for deciding with a partial set of quotes
- Circuit breakers or equivalent per-store health handling, and what they cost
- How an "out of stock" answer is qualified when some stores never replied
### Part 3 — Reducing load on the stores
How do you cut the number of calls to downstream stores? What should be cached, how long should the TTL be, and how do you prevent a thundering herd when many requests for the same popular ISBN arrive at once?
```hint Freshness has a price
Think about what goes wrong when a cached price is stale, and at which step of the flow a stale price is harmless and at which it is harmful.
```
#### What This Part Should Cover
- What is cached, how it is keyed, and how the TTL is chosen and bounded
- Coalescing concurrent requests for the same ISBN
- Other levers that reduce call volume
### Part 4 — Order and charge consistency
Placing the order and charging the customer are two separate external calls. Which goes first? How do you design compensation if the process crashes between them, and how do you prevent charging the customer twice? The interviewer probes this area in detail.
```hint Name every crash point
List where a crash can happen relative to the two calls, and ask what state you would find on restart in each case.
```
#### What This Part Should Cover
- The chosen ordering of the order and payment steps, and its justification
- A durable state machine with compensation for each failure point
- Idempotency for both external calls and for the customer's own retries
### What a Strong Answer Covers
- Explicit assumptions about asynchronous store behavior, payment semantics and price binding
- A persistent request state machine that survives crashes and restarts
- Bounded latency with explicit partial-result semantics
- Load reduction that never lets a stale price produce an order above the bid
- Exactly-once effects achieved through idempotency keys and reconciliation
- Observability: per-store latency, error rates, breaker state, and detection of stuck requests
### Follow-up Questions
- A store confirms an order but charges a price different from its quote. How do you handle it?
- How would you rank stores on more than price, for example on reliability or delivery time?
- How would you roll out a new store integration without hurting existing request latency?
Overview: Design a middleman service that takes an ISBN, bid price and payment method, queries several hundred asynchronous bookstores for the lowest price, and then orders, returns the price or reports no stock. Deep dives cover partial results and circuit breakers, caching against thundering herds, and order-and-charge consistency.