flask应用在supervisor中启动后立即退出,根本原因是debug=true启用reloader导致父进程退出;解决方法是禁用debug和reloader,改用gunicorn等wsgi服务器,并正确配置supervisor的command、directory、environment等参数确保进程稳定存活。

Supervisor 启动 Flask 应用时进程立即退出?
常见现象是 supervisord 启动后,supervisorctl status 显示 Flask 进程为 EXITED。根本原因是 Flask 默认以调试模式(debug=True)运行时会启用重载器(reloader),它会 fork 子进程并让父进程退出——而 Supervisor 只监控直接启动的主进程,父进程一退,它就认为服务挂了。
解决办法只有一条:强制关闭 reloader,并确保使用生产级 WSGI 服务器(如 gunicorn 或 waitress)。不要在 Supervisor 里直接跑 python app.py。
- 禁用
debug=True和use_reloader=True(哪怕只是临时测试也不行) - 用
gunicorn替代flask run:例如gunicorn --bind 127.0.0.1:5000 --workers 2 --timeout 30 wsgi:app -
wsgi.py文件需导出app实例(不是create_app()工厂函数,除非你用--callable显式指定)
Supervisor 配置文件里 command 怎么写才稳定?
关键不是“能不能跑”,而是“挂了会不会自动拉起”和“日志是否可追溯”。很多配置漏掉环境变量或工作目录,导致启动失败却看不到真实错误。
一个最小可用的 /etc/supervisor/conf.d/myflask.conf 示例:
[program:myflask] command=/path/to/venv/bin/gunicorn --bind 127.0.0.1:5000 --workers 2 --timeout 30 --log-level info wsgi:app directory=/opt/myflask environment=PATH="/path/to/venv/bin",PYTHONPATH="/opt/myflask" user=www-data autostart=true autorestart=true redirect_stderr=true stdout_logfile=/var/log/myflask/access.log stderr_logfile=/var/log/myflask/error.log
-
command必须用绝对路径调用gunicorn,不能依赖$PATH -
directory设为项目根目录,否则import或静态文件路径容易出错 -
environment要显式注入虚拟环境的PATH和PYTHONPATH,否则找不到包 - 别设
startsecs=0,至少留 1–3 秒确认进程真起来了,避免 Supervisor 误判为闪退
为什么 Flask 日志在 Supervisor 下全丢了?
因为 Flask 默认把日志打到 stderr,而 Supervisor 的 stdout_logfile 和 stderr_logfile 是按流重定向的——但 gunicorn 自己也会打日志,且默认不把 Flask 的 app.logger 输出合并过去。
最简单可靠的方案:关掉 Flask 的日志输出,统一交给 gunicorn 管理。
- Flask 代码中删掉或注释掉类似
app.logger.addHandler(...)的自定义 handler - 用
gunicorn的--access-logfile和--error-logfile控制输出位置 - 如果必须保留 Flask 的
app.logger.info(),要在wsgi.py里把 logger 的 level 设为INFO以上,并确保没被gunicorn的日志级别压制(比如--log-level warning就会吞掉INFO)
重启 Flask 服务时 Supervisor 报 ERROR (not running)?
这不是权限或路径问题,大概率是旧进程没杀干净,新进程 bind 端口失败,然后 Supervisor 因启动超时判定失败。尤其当你改过 gunicorn --bind 地址但没清掉残留进程时,特别容易复现。
- 先手动执行
sudo supervisorctl stop myflask,再看ps aux | grep gunicorn是否还有残留,有就kill -9掉 - 配置里加
stopwaitsecs=10,给gunicorn时间优雅关闭 worker - 换用
--bind unix:/var/run/myflask.sock替 TCP 端口,避免端口占用冲突(记得同步改 Nginx upstream) - 每次改完配置必须运行
sudo supervisorctl reread && sudo supervisorctl update,只reload不够
Supervisor 本身不理解 Python 或 Flask,它只认进程生命周期。所有异常最终都会回归到“进程是否稳定存活”这个单一判断上。别在配置里玩花样,优先保证 gunicorn 单独运行无报错,再交给 Supervisor 管理。











