Limits of proxy_ignore_client_abort: can nginx finish upstream work after the client disconnects?
0 reputation · 18 Apr 2026, 10:38 UTC
0 reputation · 18 Apr 2026, 10:38 UTC
I'm designing an nginx reverse proxy in front of a slow upstream that performs long, idempotent processing (report generation). Clients frequently disconnect before the response arrives, and I want the upstream work to still complete so results are logged and cached server-side, even though the response itself can never be delivered.
My reading of the ngx_http_proxy_module documentation is that proxy_ignore_client_abort on; keeps nginx waiting for the upstream after the client closes the connection, but the response is discarded. I'm also unsure how this interacts with proxy_read_timeout, which as I understand it bounds gaps between successive reads from the upstream rather than total request duration, so a steadily streaming upstream could run far longer than the configured value.
Assume a current stable nginx release; exact directive defaults may vary by version.
Specifically:
proxy_ignore_client_abort on, is upstream completion guaranteed only up to proxy_read_timeout gaps, or are there other limits (e.g., worker shutdown, lingering_close) that can still abort it?35775 reputation · 18 Apr 2026, 17:52 UTC
Yes: with proxy_ignore_client_abort on;, nginx keeps reading the upstream response after the client disconnects and then discards it, so the upstream normally finishes its work. But it is not a guarantee of completion — it is only a guarantee that the client disconnect itself won't trigger an abort. Every other limit that can kill the upstream connection still applies.
Your reading of proxy_read_timeout is correct: it bounds the gap between two successive reads from the upstream (default 60s in most builds), not total duration. An upstream that streams anything — even a keep-alive byte or progress chunk — resets that window and can run effectively forever. Beyond that timeout, the main abort paths are:
nginx -s reload, a binary upgrade, or a stop will eventually close in-flight upstream connections in the old workers. Long abandoned requests can pin old workers in "shutting down" state for a long time, and they will not survive an actual stop.Note that lingering_close is a red herring here: it governs how nginx closes client connections, not upstream persistence. It does not rescue upstream work if nginx tears the upstream connection down.
Not because of the client disconnect. From the upstream's perspective, the connection to nginx is a normal connection that stays open; the directive exists precisely so nginx doesn't propagate the client's close upstream. The upstream would only see a broken connection if nginx itself closes it — via proxy_read_timeout firing during a silent gap, worker shutdown, or crash. So processing is non-transactional in exactly those windows: if your report generator writes results only at the very end, a timeout at second 59 of a silent 60-second computation loses everything. Persisting intermediate or final results server-side, as you already plan, is the right mitigation.
There is no proxy-module directive that caps total upstream processing time; the per-gap semantics of proxy_read_timeout are the only built-in lever. Practical bounds have to come from elsewhere:
proxy_read_timeout and lets abandoned work accumulate, which is a resource-exhaustion risk under frequent disconnects.For genuinely long, idempotent work, proxy_ignore_client_abort is a stopgap. The standard design is asynchronous: the front service accepts the request, enqueues the job, returns 202 Accepted immediately, and the client polls a status endpoint or is notified. Completion then depends on the queue and worker, not on any proxy connection surviving.
Directive defaults and edge behavior vary across versions and packaged builds, so confirm against the ngx_http_proxy_module documentation for your deployed release. A minimal verification:
# 1. Upstream that sleeps 90s, then logs "done". Disconnect a client mid-wait
# with proxy_ignore_client_abort on: upstream log should show "done".
# 2. Set proxy_read_timeout 30s with a silent upstream:
# nginx error log should show: upstream timed out (110: Connection timed out)
# 3. During an in-flight abandoned request:
nginx -s reload
# Observe whether the old worker closes the upstream connection.One detail that would change the recommendation: whether your upstream emits any bytes during processing. If it does, proxy_read_timeout will never fire and you have no nginx-side bound at all — in that case the asynchronous pattern stops being optional.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.