Supervisor实现进程守护需满足两个前提:进程不可自行daemon化,且supervisord必须是其直接父进程;否则autorestart=true无效。常见误判是supervisorctl status显示RUNNING但实际业务进程已脱离监控,因脚本内部fork、daemon=True或sys.exit()导致子进程脱管;须检查PPID、禁用daemon选项、显式配置exitcodes、startretries等参数,并确保环境变量、路径、Python解释器路径在配置中完整声明。

Supervisor 不能直接管理 Python 脚本的“挂掉自动重启”,必须满足两个硬性前提:进程不能自行 daemon 化,且 supervisord 必须是它的直接父进程。否则 autorestart=true 形同虚设。
为什么 supervisorctl status 显示 RUNNING,但实际进程早没了?
这是最常见的误判场景——supervisord 确实启动了你的 Python 命令,但脚本内部调用了 os.fork()、启用了 daemon=True(如某些 Flask/Gunicorn 封装)、或执行了 sys.exit() 后又 fork 出子进程,导致真正干活的进程脱离了 supervisord 的子进程树。
此时 supervisord 只监控到“启动命令”退出(比如 Python 解释器执行完就退出),而不是业务进程退出,所以不会触发重启。
- 检查你的 Python 脚本是否显式调用
daemonize或使用了python-daemon库 - 若用 Gunicorn,必须加
--daemon=False(或删掉--daemon)并确保没配daemon = true在配置文件中 - Flask 默认不 daemon,但若套了 systemd-wrapper 或自写守护逻辑,就得砍掉
- 用
ps -ef | grep your_script.py看 PPID 是否等于supervisord的 PID;不是就说明已脱管
配置里 autorestart=true 不生效的典型参数组合
光开 autorestart=true 远不够,它依赖 exit code 和信号行为判断“是否异常”。Python 进程静默退出、被 SIGKILL 强杀、或 exit code 被设为 0 都会导致 supervisord 认为“正常结束”,从而不重启。
立即学习“Python免费学习笔记(深入)”;
-
exitcodes=0,2:只把退出码为 0 或 2 视作“可接受”,其余都算异常;默认是exitcodes=0,意味着只要脚本 exit(0),哪怕你主动退出,supervisord 也不重启 -
startretries=3:启动失败时重试次数,别设成 0 或 1;生产环境建议 ≥3 -
stopwaitsecs=10:发stop信号后等 10 秒再KILL,给 Python 的atexit或信号处理器留时间,避免强制中断导致状态残留 -
killasgroup=false:默认值,表示只杀主进程;如果你的 Python 脚本会 fork 出多个子进程(如多线程/多进程爬虫),需设为true,否则子进程变孤儿
Python 进程日志乱码、无法滚动、看不到 print 输出?
supervisord 默认捕获 stdout/stderr,但 Python 的输出缓冲机制会让日志延迟甚至丢失,尤其在非 TTY 环境下。
- 启动命令前加
python -u:强制未缓冲模式,例如command=python -u myapp.py -
redirect_stderr=true必须开启,否则 stderr 不进日志文件 -
stdout_logfile=/var/log/myapp.log要写绝对路径,且 supervisord 运行用户(通常是root或指定user=xxx)必须有写权限 - 日志轮转靠
stdout_logfile_maxbytes和stdout_logfile_backups控制,不配的话单个日志会无限增长 - 避免在脚本里用
logging.FileHandler写同一路径日志,会造成竞争写入和乱序
supervisord 启动后,Python 进程没起来或反复 restart?
这通常不是代码问题,而是环境隔离或路径解析失败。supervisord 启动时的工作目录、PATH、Python 解释器路径和你手动执行时往往不一致。
-
directory=/path/to/your/app必须显式指定,否则open("config.json")这类相对路径会失败 -
environment=PATH="/usr/local/bin:/usr/bin:/bin",PYTHONPATH="/opt/myapp"显式注入关键环境变量 - 用绝对路径写
command:不要command=python app.py,而要command=/usr/bin/python3.9 /opt/myapp/app.py - 如果用了 virtualenv,务必用虚拟环境里的 Python 解释器路径,例如
/opt/venv/bin/python,而不是系统全局的python - 首次启动失败时,用
supervisorctl tail -f your_program_name stderr直接看错误堆栈,比翻日志快得多
最常被忽略的一点:supervisord 本身不读取你的 shell profile(~/.bashrc、/etc/profile),所以所有 PATH、LD_LIBRARY_PATH、甚至 PYTHONIOENCODING 都得在配置里显式声明。没声明,就是没有。


















