A restaurant tablet app polls for new orders every 30 seconds. That is 2880 requests per device per day and across 50000 tablets about 144 million requests a day of which roughly 97% return nothing new. The team replaces the poll with a push notification carrying the order itself. What did they buy and what did they give up?
Show the full answer Hide the answer
What is gained, quantified
A tablet that receives 40 orders a day receives 40 pushes instead of making 2880 requests - a reduction of roughly 98.6%. Across the fleet, 144 million requests a day becomes about 2 million deliveries. On a battery-powered device the saving is larger than the request count suggests, because each poll wakes the radio, and radio wake rather than bytes dominates energy.
And latency improves in the good case: an order appears in a second or two instead of in up to 30.
What is paid
The poll was a guarantee and the push is a hope. That is the whole trade, and the rest follows from it.
- Delivery is best effort. The push service accepts your message and gives you no commitment that it arrives, that it arrives in order, or that it arrives at all. The dashboard's "delivered" counts hand-offs to the device's platform, not arrivals in your app.
- The operating system decides when your process runs. A backgrounded app on a dozing device may be allowed to run on receipt, late, or not until the user taps something.
- There is a payload ceiling - 4 KB on both major platforms - so "carrying the order" works until an order carries 30 line items and a delivery note, at which point the design silently needs the fetch it was built to avoid.
- Messages collapse. A device offline for an hour may receive one push rather than the six that were sent, because the service is entitled to replace an undelivered message with a newer one. A design where the push is the only copy of a fact loses five orders and reports success.
- A third party is now on the critical path, outside your SLO, outside your region, and not answerable to your incident process.
When the cost becomes visible
The first busy evening. A restaurant misses an order, the customer complains, and support cannot explain it because every system involved reports success. The poll's worst case was ugly and bounded at 30 seconds; the push's worst case is unbounded, and unbounded failures are the ones that become support cases rather than graphs.
The design that is actually correct
Push as a hint, never as the data.
- The push payload says only "there is something new", optionally with a sequence number. It carries no order.
- On receipt the client fetches the authoritative list of changes since its own cursor, so one lost or collapsed push costs latency and not data. Six collapsed pushes still produce one fetch that returns six orders.
- Keep a slow safety poll underneath. Five minutes instead of 30 seconds is 288 requests per device per day - still a 90% saving - and it bounds the worst case at your acceptable staleness rather than at the push service's availability.
- For a tablet that is mains-powered and on Wi-Fi, hold a persistent connection instead and treat push as the fallback for when it drops.
The decision rule: the acceptable worst-case staleness sets the safety-poll interval, and the push only improves the common case.
When this is the wrong answer
On a device that is plugged in, on Wi-Fi, and in the foreground all day - which is exactly what a restaurant tablet is - the poll was not the problem. A 30-second poll on 50000 mains-powered tablets is a server-cost question, and the cheap answers are a conditional request that returns an empty body, a longer interval, or long polling. Push earns its complexity on battery-powered devices, on devices that are usually backgrounded, and when the staleness requirement is tighter than any poll interval you can afford. Replacing a bounded mechanism with a best-effort one to save server cost on mains-powered hardware is a bad trade made for a good reason.