supervisor需显式用[program:xxx]声明php长连接脚本,关键项包括:command(绝对路径)、directory(脚本目录)、autostart/autorestart=true、startsecs≥5、指定stdout_logfile和stderr_logfile;php脚本须适配信号处理(pcntl_signal)并确保autoload路径正确,多脚本需避免端口冲突。

supervisord.conf 里怎么写 program 配置项
Supervisor 不会自动识别你的 PHP 长连接脚本,必须显式用 [program:xxx] 块声明。名字(xxx)建议用业务标识,比如 [program:wechat-socket],避免用 php-worker 这类泛称——后续查日志、启停时容易混淆。
关键配置项不能少:
-
command:必须写绝对路径,比如/usr/bin/php /var/www/app/socket.php;用which php确认解释器位置,别直接写php -
directory:设为脚本所在目录,否则相对路径(如include 'config.php')会加载失败 -
autostart和autorestart推荐都设为true,但要注意:PHP 脚本若因致命错误(Fatal error)退出,Supervisor 默认会立即重启,可能触发高频重启循环 -
startsecs建议设为5或更高,避免脚本刚启动就建立连接时被误判为“启动失败” -
stderr_logfile和stdout_logfile必须指定,否则所有echo/error_log()输出全丢进黑洞
PHP 脚本本身要适配 Supervisor 的生命周期管理
Supervisor 没有信号透传机制,SIGTERM 会被直接发给 PHP 进程,但默认 PHP 不捕获它。结果就是:执行 supervisorctl stop xxx 时,脚本可能正在处理 WebSocket 消息或数据库事务,被粗暴 kill 导致连接泄漏或数据不一致。
必须在 PHP 脚本开头加信号处理:
pcntl_signal(SIGTERM, function ($sig) {
echo "Received SIGTERM, cleaning up...\n";
// 关闭 socket、释放资源、保存状态
exit(0);
});
pcntl_async_signals(true); // PHP 7.1+
注意:pcntl_* 函数在 PHP-FPM 下不可用,只适用于 CLI 模式;如果你用的是容器环境,确认基础镜像已启用 pcntl 扩展(常见于 php:cli 镜像,但 Alpine 版需手动编译)。
为什么 supervisorctl start 后进程立刻变成 FATAL?
最常见原因是 PHP 脚本启动后立即报错退出,Supervisor 抓到非零退出码就标为 FATAL。不要只看 supervisorctl status,先查日志:
- 用
supervisorctl tail -f xxx stderr实时看错误输出 - 检查
command中的 PHP 路径是否真实存在(/usr/local/bin/php和/usr/bin/php常混用) - 确认脚本有可执行权限(
chmod +x socket.php非必需,但php要能读取它) - 如果脚本依赖 Composer autoload,确保
vendor/autoload.php路径正确——Supervisor 不走当前 shell 的pwd,directory配置不对就会require失败
一个典型错误信息是:PHP Fatal error: Uncaught Error: Class 'Ratchet\Server\IoServer' not found,本质就是 autoloader 没加载上。
多个长连接脚本共存时的端口与资源冲突
Supervisor 本身不管理端口,但你的 PHP 脚本会 bind()。如果两个 [program] 都试图监听 0.0.0.0:8080,后启动的那个必然报 Address already in use,状态变 FATAL。
解决方式只有两种:
- 每个脚本用不同端口(
8080,8081,8082),并在前端反代(Nginx)做路由分发 - 统一由一个主进程监听端口,用
pcntl_fork()派生子进程处理不同协议(如 WebSocket + MQTT),此时只需一个[program]配置
别指望 Supervisor 帮你做端口协调——它只管进程,不管网络。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











