背景:一个应用,使用 Django 开发。部署到生产环境,使用 Gunicorn 运行 Django 应用,使用 Nginx 做为前端入口。使用 Supervisor 控制 Gunicorn 服务。
现象:
- 在线生成一个报告,等待下载时,出现“后台出错“。
- 在本地调试环境下,相同的代码,能报告能正常重生成并下载。
日志
从 Django 的应用后台日志,看不到任何问题。但是从 Nginx 的 access_error.log 可以看到以下错误:
*196220 upstream prematurely closed connection while reading response header from upstream, client: x.x.x., server: xxx.xxx.com, request: "POST /some_url_path/?keyword=some_keyword HTTP/1.1",
另外,从 gunicorn 的 log 可以看到以下错误:
[2022-12-31 10:14:18 +0800] [28748] [CRITICAL] WORKER TIMEOUT (pid:28760)
第一次尝试,修改 nginx 的 proxy 超时配置
先怀疑是不是 Nginx 超时了。
在 Nginx 的代理到后台 app 的配置中,增加以下 timeout 相关的内容:
location / {
proxy_pass http://app; # <-- defined in previous lines
proxy_connect_timeout 360s; # <-- newly added
proxy_read_timeout 360s; # <-- newly added
}
但是,修改了 Nginx 配置后,还是不管用。Nignx 日志和 Gunicorn 日志中,同样的错误仍然存在。
第二次尝试,修改 Supervisor 中,Gunicorn 的超时配置
再理解一下 Nginx 的信息 - 是 Upstream 关闭了连接。也就是说,应该是 Gunicorn 服务主动关闭了连接。
于是查 Gunicorn 相关的参数,原来 Gunicorn 的缺省 timeout 时间是 30秒。因此,尝试修改 Supervisor 中 Gunicorn 的 Timeout 配置。原来的 SuperVisor 配置:
command = gunicorn app.wsgi.application -b 127.0.0.1:xxxx(port) -w 1 --log-level=debug --log-file=/var/log/gunicorn/app.log
新增关于 timeout 的配置
command = gunicorn app.wsgi.application -b 127.0.0.1:xxxx(port) -w 1 --timeout=300 --graceful-timeout=60 --log-level=debug --log-file=/var/log/gunicorn/app.log
然后要重启 Supervisor 服务。!!注意,必须重启 Supervisor服务才能使配置修改生效 !!
sudo systemctl restart supervisor
如果仅仅是使用 supervisorctl 来重启 gunicorn 这个应用是不行的。
总结
最终,第二次尝试,问题解决。
可以看到,这是 Gunicorn 网关的超时错误,增加 Gunicorn Worker 的超时时间,即可解决。