504 Gateway Timeout during long-polling upstream responses
0 reputation · 02 Jan 2023, 23:37 UTC
0 reputation · 02 Jan 2023, 23:37 UTC
In an Nginx HTTP proxy configuration, the proxy_read_timeout directive is used to manage the duration the proxy waits for a response from the proxied server. This is critical for applications utilizing long-polling or streaming data where the upstream server may maintain an open connection without sending data for extended periods.
The current behavior resets the timeout timer whenever new data is received. However, in scenarios where the upstream server is intentionally silent for a duration that exceeds the proxy_read_timeout but is still processing a valid request, Nginx terminates the connection and returns a 504 Gateway Timeout.
When balancing the need to prevent worker connection exhaustion against the requirement for long-lived upstream responses, the following uncertainties arise:
proxy_read_timeout and keep-alive settings affect the frequency of 504 errors during periods of upstream inactivity?33275 reputation · 03 Jan 2023, 06:49 UTC
To prevent 504 Gateway Timeouts during long-polling, you must ensure that the proxy_read_timeout is set to a value higher than the maximum duration the upstream server holds a request before sending a response or a heartbeat. If the upstream server is silent for 60 seconds but proxy_read_timeout is 30s, Nginx will terminate the connection.
# Example configuration for a 5-minute long-poll window
location /poll {
proxy_pass http://upstream_backend;
proxy_read_timeout 300s;
proxy_connect_timeout 75s;
proxy_send_timeout 75s;
}
Nginx does not provide a native "hard request timeout" that operates independently of the read timeout for proxying. The proxy_read_timeout is an inter-packet timer; it resets every time the proxy receives a chunk of data from the upstream server. There is no built-in directive to say "allow this request to last 10 minutes total, regardless of data flow, but timeout if no data is seen for 30 seconds." To implement a hard limit, you must manage the request lifecycle within the upstream application logic itself.
There is a critical distinction between TCP keep-alives and the HTTP read timeout:
proxy_read_timeout timer.proxy_read_timeout resets upon receiving data, these heartbeats keep the connection alive without requiring an excessively high timeout value.upstream timed out (read) in the error.log.curl -v to measure the exact elapsed time between the request and the 504 response. If the time matches your proxy_read_timeout exactly, the proxy is the bottleneck.Missing Diagnostic: Are there additional load balancers (e.g., AWS ALB, Cloudflare) in front of Nginx? If so, their independent timeout settings may trigger a 504 before the request even reaches the Nginx proxy_read_timeout threshold.
Use comments to ask for clarification. Post a solution as an answer.
33,275 reputation · 03 Jan 2023, 05:16 UTC
While proxy_read_timeout only counts idle time between packets, Nginx 1.7.11+ exposes proxy_timeout to enforce a maximum request duration that is not reset by incoming data. It behaves like a hard ceiling for the entire request/response cycle.
location /poll {
proxy_pass http://upstream;
proxy_read_timeout 60s; # idle read
proxy_timeout 180s; # total request limit
proxy_connect_timeout 10s;
proxy_send_timeout 10s;
}
When keep‑alive is enabled, keepalive_timeout controls how long an idle backend socket stays open. If this value is shorter than proxy_read_timeout, Nginx may close the upstream connection before the client receives data, which can also surface as a 504. Aligning these values helps avoid unnecessary churn.
Remember to verify the Nginx version with nginx -v before using proxy_timeout—older releases lack the directive.