Back in Module 2 we made a quiet decision: the kitchen tablet asks the server "anything new for me?" every 5 seconds. It met the requirement, it was simple, and nobody had to think about it again.
Now Tiffin wants more things to feel live. The customer app already polls its order's status every 10 seconds, and Module 5 showed what that costs the database. Customers want to see "Your food is being cooked" change to "Rider picked up your order" the moment it happens, and soon a rider moving on a map. Riders want new delivery offers the moment they appear. This module is about how news gets from the server to a screen that didn't ask for it at that exact moment. We start with the simplest answer, which you already know, and work out exactly what it costs.
The client asks, on a timer
Polling means the client sends a normal request on a fixed interval and the server answers with whatever is current.
Polling is asking the server "anything new?" on a timer, whether or not anything has changed.
The code is almost boring, which is the point:
async function watchOrder(orderId) {
const res = await fetch(`/orders/${orderId}/status`)
const order = await res.json()
render(order)
setTimeout(() => watchOrder(orderId), 10000)
}
That's it. No special server, no new protocol, no long-lived connection for the load balancer to worry about. It works through hotel Wi-Fi, office proxies and every firewall ever made, because it's just HTTP.
Two numbers decide everything
Polling has two costs, and they pull in opposite directions.
Delay. If you poll every T seconds, news that arrives just after a poll waits almost T seconds to be seen. On average it waits T/2. Poll every 10 seconds and the average customer sees "Rider picked up" 5 seconds late.
Load. Every client sends one request every T seconds whether anything happened or not. So the request rate is:
requests per second = clients watching / T
Shorter T means fresher screens and more load. You can't get one without paying in the other.
Doing the maths for Tiffin
Tiffin is now at about 200,000 orders a day, 60% of them in the 7pm to 10pm rush. That's about 11 orders a second through the evening. An order takes about 30 minutes from placing to delivery, so the number of orders in progress at once is:
11 orders/second x 1,800 seconds = ~20,000 orders in flight
Say half of those customers have the tracking screen open at any moment. That's about 10,000 screens watching an order.
| Poll interval | Requests per second | Average delay |
|---|---|---|
| 10 seconds (today) | 1,000 | 5 seconds |
| 5 seconds | 2,000 | 2.5 seconds |
| 2 seconds | 5,000 | 1 second |
| 1 second | 10,000 | 0.5 seconds |
Compare that with the rest of the app. For scale: when Module 4 began, the whole app peaked at 1,800 requests a second. A 2-second poll on this one screen would be nearly three times that, almost all of it asking a question whose answer hasn't changed.
Now look at how often there's actually news. An order goes through about six status changes in 30 minutes: placed, accepted, cooking, ready, picked up, delivered. With a 2-second poll, that's 900 polls per order to deliver 6 pieces of news. More than 99% of polls come back with "nothing changed".
That's the real problem with polling. It's not that it's slow or fragile. It's that almost all of the work is wasted.
What one poll actually costs
A wasted request isn't free, even if the answer is tiny.
- Server work. Authenticate the user, look up the order, serialise JSON. Each poll that reaches the database is a query, and Module 5 showed how precious database capacity is at dinner time.
- Bytes. Request and response headers are often 500 to 1,000 bytes, more than the status itself. Cookies make it worse.
- Battery. This one surprises people. A phone's cellular radio stays in a high-power state for several seconds after each request. Poll every 2 seconds and the radio basically never sleeps. Users notice their battery draining while the Tiffin app is open, and they blame you.
Making each poll cheaper
If you're going to poll, make the common case (nothing changed) as cheap as you can.
Ask "since when?"
Don't ask "what's the status of order 123?". Ask "has order 123 changed since version 4?". The client sends the version it last saw, and the server answers 304 Not Modified with an empty body if nothing changed. HTTP already supports this with ETags:
GET /orders/123/status
If-None-Match: "v4"
HTTP/1.1 304 Not Modified
Answer from a cache
Most polls ask about something that hasn't changed. Keep each order's current status in Redis (Module 3) and answer polls from there. A Redis read takes well under a millisecond. The database only sees the writes, not the 5,000 reads a second.
Poll slower when nothing is happening
Not every stage needs the same speed. While the kitchen is cooking, nothing visible happens for 15 minutes, so poll every 15 seconds. Once the rider is on the way, poll every 3 seconds. When the app goes to the background, stop polling entirely. This is called adaptive polling, and it often cuts load by half or more for one line of logic.
Add jitter
If 10,000 apps all start polling at the same moment (say, right after a deploy, when they all reconnect), they'll stay in lockstep and hit the server in waves: nothing, then 10,000 requests in one second, then nothing. Add a small random amount to each interval, like 10 seconds plus or minus 1, and the requests spread out evenly.
const next = 10000 + (Math.random() - 0.5) * 2000
setTimeout(() => watchOrder(orderId), next)
Price the kitchen tablets
Tiffin now has 3,000 restaurants, each with one tablet polling every 5 seconds. The restaurants ask for orders to appear "instantly", so someone proposes polling every 1 second. What does that change cost, and what does it buy?
Show one answer
At 5 seconds: 3,000 / 5 = 600 requests a second, with an average delay of 2.5 seconds.
At 1 second: 3,000 / 1 = 3,000 requests a second, five times the load, with an average delay of 0.5 seconds.
So you pay 2,400 extra requests a second to save 2 seconds on average. A restaurant gets a new order maybe every 5 minutes at peak, so almost all of those requests return nothing. Before agreeing, ask what "instantly" really means to a kitchen. A loud sound within 3 seconds might be all they need, and a 2-second poll answered from Redis gives you that cheaply. If they truly need sub-second, that's the point to stop polling and push instead.
When polling is the right answer
Polling gets a bad reputation it doesn't deserve. It's a good choice when:
- The number of watchers is small. 3,000 tablets is small. 10 million phones is not.
- A few seconds of delay is fine. Checking whether a report finished generating, refreshing a dashboard every 30 seconds, an admin page.
- Updates are frequent anyway. If something changes almost every time you'd poll, very few polls are wasted.
- You want the simplest thing that works. Polling survives server restarts, deploys and flaky networks without any special handling. The next poll just works.
It's the wrong choice when you need sub-second freshness for many watchers, or when the news is rare and the watchers are many. Tiffin's tracking screen at dinner time is exactly that second case: 10,000 watchers, six updates each over 30 minutes. In the next lesson we'll keep HTTP but stop wasting the empty answers.
What to remember
- Polling means asking the server "anything new?" on a fixed interval. It's plain HTTP, so it works everywhere and needs nothing new.
- With interval T, load is clients divided by T and the average delay is T/2. You trade one for the other.
- When updates are rare and watchers are many, almost every poll is wasted. For Tiffin's tracking screen, over 99% of polls find nothing.
- Make polls cheap: send a version and return 304, answer from a cache, slow down when nothing is happening, and add jitter.
- Polling is a good default for few watchers or relaxed delays. Move on from it when you need fast updates for many clients.