Lessons
1 · System Design Foundations
2 · APIs and Communication
3 · Capacity Estimation
4 · Core Building Blocks
5 · Databases
- 12Relational Databases and Data Modeling for System Design
- 13Database Indexes and Query Performance: How to Make Reads Fast
- 14Transactions, Isolation Levels and Concurrency Control: Preventing Race Conditions
- 15Database Replication: Primary-Replica, Read Replicas, Lag and Failover
- 16Database Sharding and Partitioning: How It Works and When You Need It
- 17SQL vs NoSQL: Data Models and How to Choose the Right Database
6 · Distributed Systems
- 18Why Distributed Systems Are Hard: Partial Failure, Timeouts and Clocks
- 19CAP Theorem and Consistency Models Explained Without the Myths
- 20Idempotency, Retries and Message Delivery Guarantees
- 21Distributed Transactions: Two-Phase Commit, the Outbox Pattern and Sagas
- 22Distributed Locks, Leases, Leader Election and Consensus
7 · Reliability and Operations
8 · Architecture and Security
9 · Interview Method and Foundation Case Studies
10 · Real-World Case Studies
- 33Design a Notification System: Email, SMS and Push at Scale
- 34Design a Chat System Like a Messaging App
- 35Design a News Feed: Fan-Out, Ranking and the Celebrity Problem
- 36Design Search Autocomplete (Typeahead)
- 37Design a Distributed Job Scheduler
- 38Design a Ticket Booking System Without Overselling
- 39Design a Payment System: Idempotency, Ledgers and Reconciliation
11 · Large-Scale Case Studies
- 40Design a Video Streaming Platform: Upload, Transcoding and Adaptive Streaming
- 41Design a Ride-Hailing System: Location, Matching and Real-Time Updates
- 42Design a Food Delivery Platform: Orders, Restaurants and Delivery Partners
- 43Design an E-Commerce System: Catalog, Cart, Checkout, Inventory and Flash Sales
- 44Design a Web Search Engine: Crawling, Inverted Indexes and Ranking
12 · Interview Readiness
Lesson 42 · Large-Scale Case Studies
Design a Food Delivery Platform: Orders, Restaurants and Delivery Partners
Design a food delivery platform where every order coordinates three parties in real time: restaurant discovery and menus as cached read models, an idempotent checkout, an order state machine driven by a saga with timeouts and compensations, dispatching delivery partners timed to food readiness, batching, live tracking, notifications, dinner-peak load, failures and the trade-offs between them.
For
SDE-2 candidates preparing for food delivery, quick commerce or logistics design questions, and engineers working on multi-party order workflows.
Level
Before you start
Read Distributed Transactions and Sagas (article 21), Event-Driven Architecture (article 27), Design a Payment System (article 39) and Design a Ride-Hailing System (article 41), whose location and matching machinery is reused here.
On this page
Key takeaways
- A food order is a long-running, three-party workflow (customer, restaurant, delivery partner), best modelled as an explicit state machine driven by an orchestrated saga with a timeout at every waiting step.
- State transitions are conditional updates on the current state, so duplicate, late and out-of-order events from apps and webhooks cannot corrupt an order.
- Restaurant discovery and menus are read-heavy and change slowly, so serve them from cached, event-fed read models; check availability and price again at checkout.
- Dispatch delivery partners so they arrive when the food is ready, using predicted preparation and travel times, and batch nearby orders when it helps.
- Design for the dinner peak and for restaurant devices going offline, with compensations (cancellation, refunds) that are automatic and visible.
At 8:30 p.m. on a Friday, a customer orders biryani. For the next 35 minutes, three parties who never talk to each other directly must stay perfectly coordinated: the restaurant must accept and cook it, a delivery partner must be nearby exactly when it is ready, and the customer must see accurate progress the whole time. If the restaurant's tablet loses Wi-Fi, if the partner's bike breaks down, or if payment confirmation arrives late, the system must notice and recover, usually without a human, and at dinner peak it does this for thousands of orders a minute.
The ride-hailing design (article 41) solved "find someone nearby and assign them". Food delivery adds a long-running, multi-party workflow with real-world timing. This case study focuses on that workflow: the order state machine, the saga that drives it, and dispatch timed to food readiness. The design is generic and illustrative; it does not describe any particular company's systems.
What you will learn
#- How to scope a three-sided marketplace and estimate its peaks.
- Discovery and menus as cached read models.
- A safe checkout, and the order state machine with a runnable example.
- An orchestrated saga with timeouts and compensations.
- Dispatch timed to food readiness, and order batching.
- Live tracking, notifications, dinner-peak load and failures.
1. The problem
#Customers browse nearby restaurants and menus, place an order and pay. The restaurant accepts and prepares it. A delivery partner picks it up and delivers it. Everyone sees status and timing in real time. Cancellations and refunds follow clear rules.
2. Clarify the requirements
#Question | Assumed answer | Impact |
|---|---|---|
Scale? | About 3 million orders a day across many cities | Estimates below |
Peaks? | Lunch and dinner; about 40% of orders between 19:00 and 22:00 | Peak factor from article 06 |
Restaurants' devices? | A tablet app per restaurant, sometimes with unreliable internet | Timeouts, fallbacks (phone call) |
Restaurant acceptance? | Must accept within about 2 minutes | Acceptance timeout |
Who delivers? | Independent delivery partners, assigned per order (batching allowed) | Dispatch service |
Payment? | Online payment before the restaurant starts cooking; cash on delivery in some cities (out of scope here) | Saga with payment |
Cancellation? | Customer can cancel before preparation starts for a full refund; later cancellations follow policy | Compensations |
Tracking? | Live map once the partner is assigned; status updates throughout | Real-time push |
Functional requirements: discover restaurants and menus; build a cart and place an order; pay; restaurant accept, prepare and mark ready; assign and track a partner; deliver; cancel and refund per policy; notify all parties.
Non-functional requirements
Quality | Target |
|---|---|
Correctness | No order charged without being fulfilled or refunded; one partner per order at a time; no duplicate orders from retries |
Latency | Restaurant list and menu p99 under 300 ms; order placement under 2 seconds |
Timeliness | Partner arrival close to food-ready time; accurate ETAs |
Availability | 99.95%; one city's problems stay in that city |
Freshness | Menu availability changes ("sold out") visible within a minute |
3. Assumptions and scale estimation
#Orders: 3 million/day -> about 35/s averageDinner peak: 40% of orders in 3 hours -> peak factor 0.4 x 24 / 3 = 3.2 -> about 110 orders/sOrder events (state changes, assignments, ETA updates): about 15 per order -> about 1,700/s at peakBrowsing: 30 million app sessions/day x 20 API calls -> 600 million/day, about 7,000/s average, about 22,000/s at peak (mostly cacheable)Delivery partners online at peak: 300,000, location every 4 s -> 75,000 location updates/sActive orders at peak: 110/s x 40 minutes average lifecycle = about 264,000 concurrent ordersRestaurants: 300,000; menus about 100 items each -> 30 million menu items (small data, read often)Conclusions: order volume is moderate (about 110 per second) but each order is a long-lived workflow with many events and external actors; browsing is high-volume but cacheable; partner locations are a high-rate stream, handled exactly as in article 41.
4. API design
#Customer: GET /v1/restaurants?lat=..&lng=..&cuisine=..&cursor=.. -> nearby, open, with delivery ETA (cached) GET /v1/restaurants/{id}/menu -> menu with availability (cached, short TTL) POST /v1/orders Idempotency-Key: ... { restaurant_id, items: [{item_id, qty, options}], address_id, quoted_total, payment_method_token } -> 201 { order_id, status: "PLACED", total } | 409 price or availability changed (with details) GET /v1/orders/{id} -> status, ETA, partner location (when assigned) POST /v1/orders/{id}/cancellation -> per policy; refund detailsRestaurant (tablet app, persistent connection plus HTTP): NEW_ORDER (push) ; POST /v1/restaurant/orders/{id}/accept {prep_minutes} | /reject {reason} POST /v1/restaurant/orders/{id}/ready ; PUT /v1/restaurant/items/{itemId}/availabilityDelivery partner (as in article 41): LOCATION (stream) ; OFFER (push) ; POST /v1/offers/{id}/accept ; POST /v1/deliveries/{id}/picked-up | /deliveredThe checkout includes the quoted total the customer saw; the server recomputes the price and rejects the order with 409 if it changed, rather than silently charging a different amount.
5. Data model
#Catalogue (owned by the restaurant service; source of truth): restaurants (restaurant_id, location, cell, hours, status open/busy/closed, avg_prep_minutes) menu_items (item_id, restaurant_id, name, price_paise, available, version)Read models (fed by events, cached): restaurants_by_cell (cell, ranking signals) ; menu documents per restaurant ; search indexOrders (owned by the order service, partitioned by city): orders (order_id PK, customer_id, restaurant_id, city, status, total_paise, version, idem_key UNIQUE per customer, created_at, eta_at) order_items (order_id, line_no, item_id, name, unit_price_paise, qty) -- prices copied at purchase order_saga (order_id PK, step, deadline_at, attempts, last_error) -- orchestrator state outbox (event_id, aggregate_id = order_id, type, payload)Dispatch (owned by the dispatch service, per city): deliveries (delivery_id, order_id UNIQUE, partner_id, status, pickup_eta, dropoff_eta) partner_assignment (partner_id PK, current_deliveries, version) -- reservation record, as in article 41The order service owns order state; the restaurant service owns menus; payment and dispatch own their data; they communicate by commands and events (articles 26 and 27).
6. Baseline architecture
#One application and one database: the order is inserted, the payment provider called inline, the restaurant polls for new orders, and an operator assigns delivery partners by phone. It works for a small town. At city scale it fails on every axis: polling tablets lag, inline payment calls make checkout fragile, manual dispatch cannot keep up at dinner, and nothing notices when a restaurant silently never accepts.
7. What breaks first?
#- Coordination: an order waits on three independent parties; each can be slow, offline or say no.
- Silent stalls: a restaurant tablet offline means an order that nobody is cooking.
- Duplicate and out-of-order events: apps retry, webhooks repeat, a "ready" tap arrives after a cancellation.
- Dispatch timing: a partner who arrives too early waits (wasting partner time); too late, food gets cold.
- Dinner peak: three times average load, all at once, in every city.
- Stale menus: a sold-out item ordered anyway.
8. Scaling the design
#Discovery and menus as read models
#Browsing dominates request volume and changes slowly, so it is served from read models built from catalogue events (CQRS, article 27; Microsoft's CQRS guidance describes read models kept in sync by events and accepting eventual consistency (CQRS pattern)):
- Nearby restaurants: indexed by geographic cell (H3 or similar, as in article 41 (H3)), with ranking signals and estimated delivery times, cached per cell for a minute.
- Menus: one document per restaurant, cached, with a short TTL and event-driven invalidation when the restaurant marks an item unavailable.
- Search: a search index fed by catalogue events.
- Availability and price are re-checked at checkout against the source of truth, so a stale menu never results in a wrong charge.
Checkout
#- Validate the cart against the catalogue: items exist, are available, prices match the quote.
- In one transaction in the order service: insert the order (
PLACED) and items with copied prices, the saga row, and an outbox eventOrderPlaced(the outbox pattern from article 21 (Transactional outbox)). The idempotency key makes a double tap return the same order. - Return
201with the order id. Everything else is asynchronous.
The order state machine
#PLACED -> PAID -> ACCEPTED -> PREPARING -> READY -> PICKED_UP -> DELIVERED \ \ \ \ `--------`--------`------------`--> CANCELLED (per policy, with compensation)Each transition is a conditional update on the current state, exactly as in the payment design (article 39). This Java program applies a realistic stream of events, including a duplicate payment webhook and a "ready" tap that arrives after the customer cancelled, and shows which ones the state machine accepts.
// File: OrderStateMachine.javaimport java.util.EnumSet;import java.util.Map;import java.util.Set;public class OrderStateMachine { enum State { PLACED, PAID, ACCEPTED, PREPARING, READY, PICKED_UP, DELIVERED, CANCELLED } // The only legal moves. Anything else is rejected, which makes duplicate and late events harmless. static final Map<State, Set<State>> ALLOWED = Map.of( State.PLACED, EnumSet.of(State.PAID, State.CANCELLED), State.PAID, EnumSet.of(State.ACCEPTED, State.CANCELLED), State.ACCEPTED, EnumSet.of(State.PREPARING, State.CANCELLED), State.PREPARING, EnumSet.of(State.READY, State.CANCELLED), State.READY, EnumSet.of(State.PICKED_UP), State.PICKED_UP, EnumSet.of(State.DELIVERED), State.DELIVERED, EnumSet.noneOf(State.class), State.CANCELLED, EnumSet.noneOf(State.class)); static State current = State.PLACED; // Mimics: UPDATE orders SET status = :to WHERE order_id = ? AND status IN (states that may move to :to) static void apply(String source, State to) { if (ALLOWED.get(current).contains(to)) { System.out.printf("%-22s %-9s -> %-9s ok%n", source, current, to); current = to; } else { System.out.printf("%-22s %-9s -> %-9s rejected%n", source, current, to); } } public static void main(String[] args) { apply("payment webhook", State.PAID); apply("payment webhook (dup)", State.PAID); // duplicate delivery apply("restaurant tablet", State.ACCEPTED); apply("restaurant tablet", State.PREPARING); apply("customer app", State.CANCELLED); // this policy allows it while preparing apply("restaurant tablet", State.READY); // arrives after the cancellation apply("partner app", State.PICKED_UP); System.out.println("final state: " + current); }}payment webhook PLACED -> PAID okpayment webhook (dup) PAID -> PAID rejectedrestaurant tablet PAID -> ACCEPTED okrestaurant tablet ACCEPTED -> PREPARING okcustomer app PREPARING -> CANCELLED okrestaurant tablet CANCELLED -> READY rejectedpartner app CANCELLED -> PICKED_UP rejectedfinal state: CANCELLEDThe duplicate webhook and the late "ready" tap change nothing. Whether a cancellation is allowed while the food is being prepared, and whether a fee applies, is a business rule; the state machine is where that rule is encoded, so it is enforced everywhere. In production, the transition table lives in the order service, each accepted transition writes an outbox event, and the rejected ones are logged and, where useful, answered with a clear message to the app ("order was cancelled").
The saga: orchestration with timeouts
#An orchestrator in the order service drives each order (orchestration suits a long flow with many steps and compensations; Microsoft's Saga guidance compares it with choreography (Saga pattern)):
Step | Command or wait | Timeout | On failure or timeout |
|---|---|---|---|
1. Payment |
| Provider-dependent; unknown outcomes resolved by status checks | Payment failed: cancel order, nothing to compensate |
2. Restaurant acceptance |
| 2 minutes, with a reminder and then an automated phone call | Rejected or no answer: cancel order, refund |
3. Preparation | Wait for | Estimate plus a margin | Overdue: notify customer, nudge restaurant, adjust ETA |
4. Dispatch |
| Partner found within a few minutes | Escalate search radius, offer incentives; as a last resort cancel and refund |
5. Pickup and delivery | Wait for | ETA-based | Partner stuck: reassign (food may need remaking: policy) |
6. Settlement | Capture or finalise payment; record restaurant and partner earnings | n/a | Retried until done (retryable steps after the pivot) |
The pivot is the restaurant starting preparation: before it, cancellation is cheap and fully refundable; after it, food exists and policy decides who pays. Saga state is persisted in order_saga with a deadline_at; a scheduler (article 37) wakes the orchestrator when deadlines pass, so a crashed orchestrator instance or a silent restaurant never leaves an order stuck.
Dispatch timed to food readiness
#Assigning a partner the moment an order is placed wastes partner time (they wait at the restaurant for 20 minutes); assigning too late makes food wait. The dispatch service instead aims for the partner to arrive just as the food is ready:
ready_at = accepted_at + predicted_prep_time (restaurant history, items, current load)travel = predicted time for a candidate partner to reach the restaurantdispatch when: now + travel ~ ready_at - small buffer- Candidates come from the same in-memory, cell-indexed location service as article 41.
- Offers and reservations use the same conditional updates on
partner_assignment, so a partner never gets conflicting assignments. - Batching: a partner can carry two orders from the same or nearby restaurants going in similar directions, if neither customer's ETA suffers beyond a threshold. Batching is an assignment optimisation run over a short window for each area.
- Predictions (preparation time, travel time) come from models trained on history; when predictions are poor, the system falls back to simpler rules and wider buffers.
Live tracking and notifications
#- Once assigned, the partner's location is pushed to the customer's app over its connection, as in article 41.
- Status changes (accepted, preparing, picked up, arriving) go through the notification platform (article 33): in-app updates while the app is open, push notifications otherwise (for example via Firebase Cloud Messaging (FCM)).
- The restaurant tablet keeps a persistent connection for new orders, with a polling fallback and an automated call if a new order is not acknowledged.
Handling the dinner peak
#- Per-city partitioning of order, dispatch and location services; each city scales independently.
- Autoscale ahead of the known daily peak, not only reactively.
- Restaurant throttling: restaurants can switch to "busy" (longer prep estimates, or temporarily closed), and the platform can automatically stop sending orders to a restaurant whose queue is growing.
- Demand shaping: delivery fees or longer ETAs in areas where partner supply is short; honest "high demand" messaging.
- Caching absorbs browsing spikes; checkout and order flows get priority over browsing when shedding load (article 23).
The evolved architecture
#Customer app --> API gateway --> Discovery (cached read models, search) <-- catalogue events --> Order service (orders + saga + outbox, per city) |-- Payment platform (article 39) |-- Restaurant service --> tablet app (push, polling fallback, auto-call) |-- Dispatch service (per city) <-- Location service (partners, article 41) `-- Scheduler (saga deadlines)Order events (outbox --> stream) --> Notifications, tracking, analytics, earnings, ratings9. Failure scenarios and reliability
#Failure | Effect | Response |
|---|---|---|
Restaurant tablet offline | New order not seen | Push plus polling fallback; acceptance timeout triggers an automated call; then cancel and refund |
Restaurant rejects (item out of stock) | Order cannot proceed | Compensation: cancel and refund; mark the item unavailable in the catalogue |
Payment outcome unknown | Cannot proceed safely | Order waits in |
No partner available | Food ready, nobody to carry it | Widen search, incentives, batch; keep the customer informed; last resort: cancel with refund per policy |
Partner has an accident or app dies after pickup | Food in transit, partner unreachable | Detect missing location updates; operations team contacts; reassign or refund; incident handling |
Duplicate or late events | Possible state corruption | Conditional transitions; idempotent handlers |
Orchestrator instance crashes | Sagas paused | State persisted; another instance resumes; deadlines enforced by the scheduler |
City-level outage of a service | Orders in that city affected | Per-city failover; other cities unaffected |
10. Consistency
#- Order state: strongly consistent in the order service (single owner per order, conditional transitions).
- Cross-service state (payment, restaurant, dispatch): eventually consistent through the saga, with every intermediate state visible to the user.
- Menus and discovery: eventually consistent (a minute), re-validated at checkout.
- Partner assignment: strongly consistent per partner (reservation record).
- ETAs: predictions, continuously updated; presented honestly as estimates.
11. Security
#- Authorisation per party: customers see only their orders; restaurants only their orders and menu; partners only the deliveries assigned to them, and only for the duration needed.
- Privacy: customer address and phone are revealed to the partner only after assignment and hidden after delivery; phone numbers are masked through call proxying.
- Fraud: fake orders, refund abuse ("food never arrived"), promotion abuse, colluding partners; use delivery evidence (location trail, photo at doorstep where appropriate), account history and limits.
- Restaurant and partner payouts: changes to bank details require strong verification and are audited (article 28).
- Payments: tokens only, idempotent calls, verified webhooks (article 39).
12. Observability
#Signal | Why |
|---|---|
Order funnel: placed, paid, accepted, ready, picked up, delivered, cancelled (per city, per minute) | The business heartbeat; sudden drops reveal outages |
Restaurant acceptance time and timeout rate | Tablet connectivity and restaurant health |
Prep-time and ETA prediction error | Dispatch quality |
Partner wait time at restaurants; food wait time for partners | Dispatch timing |
Orders stuck in any state beyond its deadline | Saga health |
Cancellations and refunds by reason | Experience and fraud |
Browse latency and cache hit ratios | Discovery performance |
13. Trade-offs
#Decision | Chosen | Alternative | Why |
|---|---|---|---|
Workflow | Orchestrated saga with deadlines | Choreography across services | Many steps, timeouts and compensations; one place to see each order |
State changes | Conditional transitions in one owner | Any service writes order status | Duplicates and late events cannot corrupt orders |
Discovery | Event-fed cached read models | Query the catalogue directly | Read volume and latency; re-check at checkout |
Dispatch timing | Arrive at predicted ready time | Assign immediately | Less partner waiting, fresher food; depends on predictions |
Batching | When ETAs stay within thresholds | Never batch | Partner efficiency versus customer delay |
Partitioning | By city | Global services | Local operations, contained failures |
14. The final interview answer
#"Food delivery coordinates three parties for every order. About 3 million orders a day means around 110 orders a second at the dinner peak, plus heavy but cacheable browsing and a 75,000-a-second partner location stream.
Discovery and menus are read models fed by catalogue events and cached per area; price and availability are re-checked at checkout. Checkout is idempotent and writes the order, its items with copied prices, saga state and an outbox event in one transaction. An orchestrator in the order service then drives an explicit state machine: payment through the payment platform, restaurant acceptance with a two-minute deadline and an automated call fallback, preparation, dispatch, pickup and delivery. Every transition is a conditional update on the current state, so duplicate and late events are harmless, and deadlines are enforced by the scheduler. Compensations cancel and refund automatically before preparation starts; after that, policy decides.
Dispatch reuses the ride-hailing location index and reservations, but times assignment so the partner arrives when the food is predicted to be ready, and batches nearby orders when ETAs allow. Customers see live tracking and push updates. Everything is partitioned by city, autoscaled ahead of dinner, and restaurants can be throttled when they fall behind."
Exercises
#Exercise 1
Design the timeouts
#For each waiting step (payment, restaurant acceptance, preparation, partner assignment, pickup, delivery), propose a timeout, what the system does when it fires, and who is notified.
Exercise 2: Dispatch timing arithmetic
#An order is accepted at 20:00 with a predicted preparation time of 18 minutes. The best candidate partner is 7 minutes away now, and you want them to arrive 2 minutes before the food is ready. When should the dispatch offer be sent? What if the partner declines and the next candidate is 11 minutes away?
Exercise 3: The silent restaurant
#At dinner peak, a popular restaurant's tablet loses connectivity for 15 minutes. Twelve orders arrive in that time. Walk through what happens to each order and what customers see.
Exercise 4: Batching decision
#A partner is heading to restaurant R for order A (customer 3 km east). Order B from restaurant R becomes ready 4 minutes later, for a customer 3.5 km east-north-east. When should the system batch B with A, and what limits would you set?
Show solutionHide solution
Step | Timeout | Action when it fires | Notified |
|---|---|---|---|
Payment | Provider-dependent, for example 5 minutes for app-approval methods | Resolve via status query; if failed or abandoned, cancel the order | Customer ("payment not completed") |
Restaurant acceptance | 2 minutes (reminder at 1 minute, automated call at 1.5) | Cancel and refund; flag the restaurant (possibly set to busy or closed) | Customer, restaurant, operations if repeated |
Preparation | Restaurant estimate plus 50% | Nudge restaurant; update customer ETA; at a hard limit, offer cancellation with refund | Customer, restaurant |
Partner assignment | 5 minutes after the planned dispatch time | Widen radius, raise incentives; at 15 minutes, operations alert; last resort cancel and refund | Customer (delay message), operations |
Pickup | 10 minutes after arrival at the restaurant | Check with the restaurant and partner; reassign if needed | Partner, restaurant |
Delivery | Predicted ETA plus 15 minutes, or no location updates for 5 minutes | Contact partner; operations escalation; refund or redelivery per policy | Customer, operations |
Exercise 2
Show solutionHide solution
Food ready at 20:18; target arrival 20:16. The partner needs 7 minutes, so send the offer at about 20:09 (plus a small allowance, say 30 to 60 seconds, for the partner to accept: around 20:08).
If that partner declines at, say, 20:09:15 and the next candidate is 11 minutes away, they would arrive around 20:20, two minutes after the food is ready. Options: accept the small delay (update the customer's ETA), or, knowing decline rates, send offers slightly earlier for orders where the nearest candidates are far, or send the offer to a closer partner who is finishing a nearby delivery. Good dispatch systems treat the buffer as a function of decline probability and supply.
Exercise 3
Show solutionHide solution
For each of the 12 orders:
- Order placed and paid; the restaurant service pushes
NEW_ORDER, which never arrives; the tablet's polling also fails (no connectivity). - At 1 minute, a reminder push (fails); at 1.5 minutes, an automated phone call to the restaurant's registered number. If staff answer and accept by phone, the order moves to
ACCEPTEDthrough an operations path. - If not accepted by 2 minutes, the saga cancels and refunds automatically. The customer sees "the restaurant could not accept your order; your refund has been initiated", plus suggestions of similar restaurants.
- After the first few timeouts, the platform automatically marks the restaurant temporarily unavailable, so later customers do not order from it at all; the listing reappears when the tablet reconnects.
So perhaps the first 2 or 3 orders are cancelled (or saved by phone), and the remaining customers never see the restaurant as open during the outage, which is far better than 12 orders silently waiting.
Exercise 4
Show solutionHide solution
Batch B with A when:
- the partner can wait for B (ready 4 minutes later) or arrives late enough that both are ready together, without A's food waiting too long (for example, A waits at most 3 to 5 minutes extra);
- the route to both customers adds little to A's delivery (A first, then B, or vice versa), keeping each customer's ETA within a threshold compared with separate delivery (for example, no more than 5 to 8 minutes later than a dedicated partner would achieve);
- the partner's vehicle can carry both orders, and food types tolerate the extra time (ice cream versus biryani).
Limits: at most 2 (or 3) orders per batch; maximum extra time per order; batch only in high-demand periods when dedicated partners are scarce (otherwise the customer experience cost is not worth it); and recompute ETAs immediately for both customers so their tracking stays honest.
Where to go next
#- Next: Design an E-Commerce System: Catalog, Cart, Checkout, Inventory and Flash Sales, which has a similar order saga but very different inventory and traffic problems.
- Related: sagas (article 21), payments (article 39) and dispatch (article 41).
Sources & further reading
- Technology
- Software Engineering
- #case study
- #distributed systems
- #microservices
- #roadmap
- #scalability
- #system design
- #system design interview
Connected lessons
Linked from 1 guide
Other pages in the library that point here.
Keep reading
More in Technology →Guide · Technology
Start Here: Your Roadmap from Zero to Job-Ready DSA
Guide · Technology
Heaps and Priority Queues
Guide · Career
A LinkedIn Profile That Gets Recruiter Messages

