flask应用不能直接用flask run上生产,因其默认werkzeug开发服务器单进程、无超时、不支持多worker且无热更新;应使用gunicorn承载+supervisor管理,gunicorn通过--reload轮询.py文件实现开发热更,supervisor通过sighup信号触发gunicorn平滑重启。

Flask应用为什么不能直接用 flask run 上生产?
因为 flask run 默认启用的是 Werkzeug 开发服务器,它单进程、无超时控制、不支持多 worker,遇到请求阻塞就整个挂掉;更关键的是——它没有热更新能力,改了代码必须手动 kill 再重启,线上服务根本不可接受。
真正可行的路径是:用 Gunicorn 作为 WSGI 服务器承载 Flask 应用,再用 Supervisor 监控并管理 Gunicorn 进程生命周期。热更新的核心不在 Flask,而在 Gunicorn 的 reload 机制和 Supervisor 的信号转发配合。
如何配置 Gunicorn 支持代码变更自动重启?
Gunicorn 本身不监听文件变化,但提供 --reload 参数,它会启动一个额外的监控线程,轮询 Python 模块的 mtime(默认每 1 秒),一旦检测到源码或依赖模块被修改,就平滑重启 worker 进程。
注意几个关键点:
-
--reload只适用于开发/测试环境,禁止在生产环境开启(轮询开销+安全隐患) - 它只监控
.py文件,不会响应.html、.json或配置文件变更,除非这些文件被 import 进 Python 模块 - 若使用
--reload-extra-file,可手动添加额外监控目标,比如:--reload-extra-file config.py --reload-extra-file templates/base.html - 推荐搭配
--reload-delay 0.5缩短轮询间隔,避免修改后等待太久才生效
典型启动命令示例:
gunicorn --bind 127.0.0.1:8000 --workers 2 --reload --reload-delay 0.5 --access-logfile - myapp:app
Supervisor 怎么配合 Gunicorn 实现可控热更新?
Supervisor 不负责检测代码变更,但它能可靠地接管 Gunicorn 进程,并响应外部信号完成“软重启”。真正的热更新流程是:改完代码 → 手动触发 supervisorctl restart myapp → Supervisor 向 Gunicorn 主进程发 SIGHUP → Gunicorn 平滑拉起新 worker、等旧 worker 处理完请求后退出。
关键配置项(/etc/supervisor/conf.d/myapp.conf):
-
command必须指向 Gunicorn 启动命令,且不能带--reload(否则 Supervisor 无法干净接管) -
autostart=true和autorestart=unexpected是基础保障 -
stopsignal=TERM是必须项:Gunicorn 默认响应TERM做优雅停止;若写成HUP,Supervisor 会误判为异常退出而反复拉起 -
environment=PATH="/path/to/venv/bin"确保调用的是虚拟环境里的gunicorn
配置片段示例:
[program:myapp] command=/path/to/venv/bin/gunicorn --bind unix:/tmp/myapp.sock --workers 3 --access-logfile - myapp:app directory=/opt/myapp user=www-data autostart=true autorestart=unexpected stopsignal=TERM environment=PATH="/path/to/venv/bin"
热更新失败的常见表现和排查方向
执行 supervisorctl restart myapp 后页面没变、日志没刷新、甚至报 502,大概率是以下某处断了链路:
- Gunicorn 进程没真正退出:检查
ps aux | grep gunicorn是否残留旧进程,可能是stopsignal配错或 worker 卡死 - 新进程启动失败:看
supervisorctl tail myapp stderr,常见原因是ImportError(路径不对)、PermissionError(socket 文件权限/目录不可写) - Nginx 没重载 upstream:如果前端套了 Nginx,改完后要
nginx -s reload,否则仍转发到旧 socket 或端口 - Python 缓存干扰:
.pyc文件或__pycache__目录未更新,可加--reload临时验证,或部署脚本中加入find . -name "*.pyc" -delete && find . -name "__pycache__" -delete
最稳妥的更新节奏其实是:停流量 → 更新代码 → supervisorctl restart → 验证日志和接口 → 恢复流量。别迷信全自动,尤其涉及数据库模型或配置结构变更时。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











