Swiggy live tracking
Not climbed yetModel answer
The partner's app sends its location every few seconds:
POST /partners/me/locationwith latitude, longitude and a timestamp. The server keeps the latest location per partner; the live view needs nothing older.The customer's app calls
GET /orders/{id}/tracking, which looks up the order's partner and returns that location and an ETA. The simplest version polls every few seconds; pushing updates can come later.Tables:
orders(id, customer_id, restaurant_id, partner_id, status)andpartner_locations(partner_id, lat, lng, updated_at), one row per partner, overwritten on each update.Check access on every call: customers may see only the partner on their own active order, and only until it is delivered. A live location is personal data.
Model answer
That is 125,000 writes a second. As a new SQL row each time, it would be over 10 billion rows a day at that rate, and almost nobody reads them.
Keep the latest location in Redis: one key per partner, overwritten on each update, with a TTL (
SET loc:p42 ... EX 30) so partners who go offline drop out by themselves. 125,000 small writes a second fits a few Redis shards, split by partner id.The history matters later (disputes, route replays, better ETAs) but not now. Write each update to Kafka, partitioned by partner id, and let a consumer load it into cheap storage in batches.
Make each update cheap as well: skip it when the partner has not moved, and keep a persistent connection (WebSocket or MQTT) open from the app, so every update is not a new HTTPS handshake.
Model answer
The customer's app opens a WebSocket (or Server-Sent Events, enough for one-way updates) to a tier of connection servers. The server that holds the connection subscribes to a channel for that order,
order:123.When a location arrives, the ingest service looks up the partner's active order and publishes to its channel (Redis pub/sub, or a fan-out service fed by Kafka). Only the server holding that customer's connection is subscribed, so only it receives the update and passes it on.
Size the tier by connections. Say 1 million customers watch at peak and each server keeps 50,000 connections to leave headroom: about 20 servers, behind a load balancer that handles long-lived connections.
Connections drop on every deploy and every patchy network. The app reconnects with backoff and jitter, reads the latest location once from Redis, then resumes the stream, and falls back to polling if it cannot connect. On the map, it animates between points so the marker glides instead of jumping.
Model answer
Keep free partners in a geospatial index. Redis GEO does it directly:
GEOADD free_partners 77.59 12.97 p42, thenGEOSEARCH free_partners FROMLONLAT 77.60 12.95 BYRADIUS 3 km ASC COUNT 20. By hand, split the map into geohash or H3 cells, keep the free partners per cell, and search the restaurant's cell plus its neighbours, because the closest partner may be just across a cell border. Widen the ring if too few turn up.Claim atomically. Two orders can pick the same partner at the same instant, so the claim must be one step only one can win:
SET claim:p42 order123 NX EX 30in Redis, orUPDATE partners SET order_id = $1 WHERE id = $2 AND order_id IS NULL. The loser moves on to its next candidate, and the partner gets a few seconds to accept before the offer moves on too.Straight-line distance is not travel time. Rank candidates by road ETA from a routing service, and time the assignment so the partner reaches the restaurant when the food is ready, not ten minutes early.
Then batching: a partner already carrying an order from the same restaurant, heading the same way, can take a second one. Waiting a few seconds to batch saves partners and money but costs speed, the trade-off to name.
