Design DoorDash - Follow-up questions

Here is solutions for Design DoorDash.

1. High-level Design

doordash

2. Evaluate the solution

2.1. Positives

  • Using Redis with geo-indexing for real-time driver location tracking is an excellent choice that enables efficient proximity-based driver matching

  • Implementing a retry queue for ignored driver requests with TTL-based locking prevents driver spam while ensuring orders get fulfilled

  • Separating search functionality with ElasticSearch for items/restaurants while using DynamoDB for core data provides appropriate read/write optimization

2.2. Potential Issues

  • Missing Order Assignment Logic

    • The design doesn’t specify how drivers are selected from the geo-index results or how optimal route calculation happens

    • This could lead to inefficient driver assignments where the closest driver isn’t necessarily the best choice considering their current route

    • The functional requirement for “optimal route for destinations” is not addressed in the current architecture

  • Synchronous Payment Processing Bottleneck

    • The Order Service directly calls Stripe synchronously before notifying drivers

    • This creates a bottleneck where slow payment processing (2-5 seconds) blocks the entire order flow
    • At 1M orders/day (~12 orders/second peak), this could cause significant delays and timeouts
  • Undefined Driver State Management

    • There’s no clear mechanism for tracking driver availability (busy, available, offline)

    • Multiple orders could be assigned to the same driver simultaneously if they’re just using geo-proximity

    • This violates the requirement that “drivers should not be spammed with multiple orders”

2.3. Follow-up Questions

  1. How does the system handle partial order failures when ordering from multiple restaurants?

  2. What happens when a driver accepts an order but then becomes unavailable (app crash, network issues)?

  3. How do you ensure consistency between the driver’s location in Redis and their actual order assignment status?

  4. How does the retry queue determine which drivers to try next after an ignore?

  5. What’s the strategy for handling peak hours when driver availability is low?

  6. How do you prevent race conditions when multiple orders are trying to lock the same driver?

3. Data Flow

Yes. For an interview, I’d present the end-to-end flow as one main happy path, then be ready to drill into 4 places: search, order creation + payment, driver dispatch, and failure recovery.

The cleanest version is this:

User opens app and searches for restaurants or an item.

If they search by restaurant name or cuisine, the request goes through API Gateway to Search Service, which queries Elasticsearch for nearby restaurants. Elasticsearch is the serving index because it supports text search plus geo filtering. The results return restaurant summaries like restaurantId, name, rating, ETA, and delivery fee.

If the user opens a restaurant page, API Gateway calls Restaurant/Menu Service, which reads menu data from DynamoDB. If needed, menu data is also cached in Redis.

If the user searches for a food item like “burger”, Search Service queries Elasticsearch for matching items, then groups results by restaurant and filters by distance and availability.

Once the user adds items to cart and clicks checkout, the request goes to Order Service.

Order Service first validates the cart. It checks restaurant status, menu item availability, pricing, fees, and delivery address. Then it creates an order record in DynamoDB with state like PENDING_PAYMENT_AUTH or CREATED.

At the same time, it kicks off payment authorization, not capture. That means Payments Service talks to Stripe to place a hold on the customer’s card. This should be asynchronous with idempotency keys, so retries don’t double charge.

If auth succeeds, the order state becomes READY_FOR_DISPATCH. Then Order Service publishes an OrderReady event to a queue or Kafka topic.

Now dispatch starts.

Matching Service consumes OrderReady. It gets restaurant location and delivery location, then queries Redis GEO for nearby drivers. Redis only gives candidate proximity, not the final choice.

For each candidate driver, Matching Service checks driver state from Redis or Driver State Service. A driver must be idle, recently heartbeating, and not under cooldown. Then the service scores candidates using something like:

score = pickup_eta + delivery_eta + detour_penalty + batching_penalty

If you want a simple interview answer, say you start with nearest idle driver. If pressed, say production systems use ETA-based ranking, not just distance.

Matching Service sends an offer to the best 1–3 drivers through Notification Service. At the same time, it atomically places a temporary lock like driver:{id}:active_offer = orderId with TTL in Redis. That prevents spam and duplicate assignment.

Driver receives push notification and accepts.

Acceptance goes back through API Gateway to Matching Service. Matching Service atomically verifies that: the offer is still valid, the driver is still available, and the order is still unassigned.

If valid, it marks the driver assigned, updates order state to DRIVER_ASSIGNED, and emits DriverAssigned.

Only now do you move from payment auth to capture. Payments Service captures the Stripe payment. If capture succeeds, order becomes CONFIRMED.

Then Notification Service tells: the user: driver assigned, ETA shown the restaurant: start preparing the driver: navigation details

During delivery, Driver App sends location updates periodically to Location Service. Location Service writes latest coordinates into Redis GEO and updates heartbeat TTL. User tracking reads from this cache for low latency.

As the order progresses, Driver App or restaurant system sends status changes: ARRIVED_AT_STORE ORDER_PICKED_UP DELIVERING DELIVERED

Order Service persists these transitions in DynamoDB and emits events so user notifications and tracking stay updated.

Once delivered, final state becomes COMPLETED. Payment is already captured, so this is mostly bookkeeping, receipt generation, analytics, and eventual archival.

4. Grill-down questions

If they drill down, these are the most likely areas:

For search drill-down, explain why Elasticsearch and DynamoDB are both there. DynamoDB is source of truth. Elasticsearch is the read-optimized search index, updated asynchronously via CDC or event pipeline. If ES is stale, user may click a restaurant and see menu/item unavailable, so cart validation must happen again at checkout.

For payment drill-down, explain auth vs capture. You don’t want to capture before a driver is assigned, because if dispatch fails you now need refunds. So place a hold first, capture after assignment, and rely on Stripe webhooks for final reconciliation.

For dispatch drill-down, explain race prevention. Redis GEO finds candidates, but assignment uses an atomic lock or compare-and-set so two orders cannot assign the same driver. You also keep tried_drivers per order so retries don’t ping the same driver repeatedly.

For failure drill-down, walk through three cases: driver ignores offer: offer TTL expires, Matching Service tries next driver batch driver accepts then goes offline: short grace period, then re-dispatch payment capture fails after assignment: cancel assignment or reassign based on business policy, and notify restaurant/user

If they ask about multiple restaurants, I would simplify by saying the system should split cart into child orders per restaurant. Each child order has separate dispatch and fulfillment. Parent order is just a user-facing grouping abstraction. That avoids a lot of messy partial failure logic.

5. Follow-up questions

5.1. How does the system handle partial order failures when ordering from multiple restaurants?

5.2. What happens when a driver accepts an order but then becomes unavailable (app crash, network issues)?

5.3. How do you ensure consistency between the driver’s location in Redis and their actual order assignment status?

5.4. How does the retry queue determine which drivers to try next after an ignore?

5.5. What’s the strategy for handling peak hours when driver availability is low?

5.6. How do you prevent race conditions when multiple orders are trying to lock the same driver?

5.7. Other questions with same topic but in other threads

July 22, 2026