DEV Community

Cover image for The Moving Bike on Your Food App: How Live Order Tracking Actually Works (in Azure)
Vignesh Athiappan
Vignesh Athiappan

Posted on

The Moving Bike on Your Food App: How Live Order Tracking Actually Works (in Azure)

You order biryani on Swiggy. You keep refreshing. A little bike icon crawls across the map toward your house. It feels like magic.

It isn't. It's four tools, each doing exactly one job. This post breaks the whole thing down using that one everyday moment — no heavy theory, just the flow.

Swiggy runs on AWS; I've mapped everything to its Azure equivalent so you can build the same thing.


The cast: 4 tools, 4 jobs

Tool Its one job Real-life analogy
Service Bus Carry the order — must never be lost Registered post
Event Hubs Carry the GPS firehose — millions of pings CCTV recording
Redis Hold "where's the bike right now" Sticky note
Cosmos DB / SQL Keep the order forever Filing cabinet

The whole trick is: never make one tool do two jobs. Each is great at exactly one thing.


The journey, step by step

1. You tap "Place Order"

Tap → Service Bus (1 order message) → Order Service → saved to Cosmos
Enter fullscreen mode Exit fullscreen mode

Service Bus = reliable, so the order can't vanish or double. Cosmos = the permanent record.

2. Restaurant gets notified

Order Service → Service Bus → Restaurant App: "New order!"
Enter fullscreen mode Exit fullscreen mode

A discrete command that must arrive → Service Bus again.

3. Rider assigned — and GPS starts immediately

Rider assigned → phone GPS starts streaming → Event Hubs
Enter fullscreen mode Exit fullscreen mode

This is why you can watch the bike drive to the restaurant first, then to you. GPS begins at "assigned," not at "picked up."

4. The firehose hits the pipe

Bike GPS (every ~4 sec) → Event Hubs
Enter fullscreen mode Exit fullscreen mode

One bike is tiny. 500,000 bikes = ~125,000 pings/sec. Event Hubs swallows it without blinking.

5. A processor turns the firehose into one value

Event Hubs → Stream Processor → Redis: "bike_4471 = 12.97, 77.59"
Enter fullscreen mode Exit fullscreen mode

Each new ping overwrites the last one in Redis. 15 pings a minute collapse into 1 sticky note.

6. You refresh the map

Your app → reads Redis (1 value, <1ms) → 🛵 dot moves
Enter fullscreen mode Exit fullscreen mode

You read Redis, not Event Hubs. It's instant because it's a single lookup, not a firehose.

7. Delivered — keep only what matters

Order Service → status "Delivered" → Cosmos
Processor → sampled trail → Lakehouse
Enter fullscreen mode Exit fullscreen mode

The raw 4-second pings are thrown away. Kept: the final order (Cosmos) + a thinned route trail (Lakehouse).


The one idea that makes it all click: TWO LANES

Beginners picture one straight line. It's actually two independent lanes that meet only at Redis.

WRITE lane (always on, background):   GPS → Event Hubs → Processor → Redis
READ lane  (only when you refresh):   You → Redis → 🛵
Enter fullscreen mode Exit fullscreen mode
  • The processor is always filling Redis in the background.
  • Your refresh only reads Redis.
  • You never touch Event Hubs or the processor.

Analogy: a chef (processor) keeps refilling the buffet tray (Redis). You (refresh) grab from the tray. You never wait for the chef.


The 4 confusions everyone hits (and the fix)

"Isn't the cached position outdated?"
It can be — by design. You only cache things where "a few seconds old is fine" (bike position). You never cache the wallet balance. Redis holds a fresh value because the processor overwrites it every few seconds.

"Is Event Hubs just a database?"
No. A database lets you ask "give me bike 4471's location." Event Hubs can't — it only lets you read the stream front-to-back, like a ticker. It's a log that forgets (data expires after 1–7 days). Filing cabinet vs conveyor belt.

"Event Hubs overwrites, so no history?"
Swapped tools. Event Hubs KEEPS history (every ping, in order, for days). Redis is the one that overwrites. History survives in Event Hubs short-term and Lakehouse long-term.

"Won't the database get the same 125k/sec firehose anyway?"
No — the consumer is a filter + funnel, not a pass-through:

  • Reduce — Redis overwrites; only a sampled trail is kept (drop ~87%)
  • Batch — 1,000 events → 1 bulk write
  • Smooth — the buffer absorbs the dinner-time spike so the DB sees a calm, flat rate

By the time data reaches the DB, it's a trickle — sampled, batched, and calm.


Bonus: how does it say "25 mins" before the food is even made?

It's a prediction, not a measurement. An ML model adds three guesses:

ETA = prep time + rider-to-restaurant + restaurant-to-you
Enter fullscreen mode Exit fullscreen mode
Piece Guessed from
Prep time This restaurant's history for this dish + kitchen load
Pickup travel Rider GPS distance + live traffic
Delivery travel Route distance + live traffic

That's why your ETA sometimes jumps 25 → 35 mid-order: the model re-adjusts as reality changes.


Why not just use one big tool?

Because every tool is great at one thing and bad at the others:

If you forced Event Hubs to also be the database If you forced Redis to keep history
Can't look up by key Runs out of memory fast
Data expires and vanishes Loses "current" clarity

Splitting the jobs is the same trade-off principle behind all system design: pick the right tool for each job, and accept that no single tool wins at everything.


The whole thing in 3 lines

Order → Service Bus → Cosmos (keep forever)
GPS → Event Hubs → Redis (keep "now") → your map
The database never sees the firehose — only the trickle that matters.

Next time you watch that bike crawl toward your door, you'll know: it's not magic. It's a write lane quietly filling a sticky note, and a read lane grabbing it every time you refresh.

Top comments (0)