使用 Supervisor 管理进程时,如果你的程序会派生子进程,默认配置可能导致子进程在主进程停止后成为孤儿进程,继续占用资源。
问题场景
典型情况包括:
- Shell 脚本启动的后台进程
- Python/Node.js 程序派生的 worker 进程
- 使用
fork()创建的子进程
当你执行 supervisorctl stop 或 restart 时,Supervisor 默认只向主进程发送信号,子进程可能不会被正确终止。
推荐配置
在程序配置中添加以下两个参数:
[program:your_program]command=/path/to/your/program; 其他配置...
; 允许杀死该进程组内的所有进程killasgroup=true; 允许停止该进程组内的所有进程stopasgroup=true参数说明
| 参数 | 默认值 | 作用 |
|---|---|---|
killasgroup | false | 向整个进程组发送 SIGKILL 信号 |
stopasgroup | false | 向整个进程组发送 stop 信号(SIGTERM) |
工作原理
- stopasgroup=true:执行
supervisorctl stop时,信号发送给整个进程组,而不仅是主进程 - killasgroup=true:当进程在
stopwaitsecs超时后仍未退出,SIGKILL 信号发送给整个进程组
完整配置示例
[program:myapp]command=/usr/bin/python3 /app/main.pydirectory=/appuser=www-dataautostart=trueautorestart=truestopwaitsecs=10killasgroup=truestopasgroup=truestdout_logfile=/var/log/myapp/stdout.logstderr_logfile=/var/log/myapp/stderr.log何时需要这些配置
✅ 建议开启的场景:
- 程序会创建子进程或 worker
- 使用 shell 脚本作为启动入口
- 程序使用多进程模式(如 gunicorn、celery)
❌ 可以不开启的场景:
- 单进程程序
- 程序内部已实现优雅关闭逻辑,能正确处理子进程
总结
将 killasgroup=true 和 stopasgroup=true 加入你的 Supervisor 配置,可以确保在停止或重启服务时,所有相关进程都被正确终止,避免僵尸进程和资源泄漏。
Thanks for reading!