在 PHP 项目中使用 Supervisor 管理 PHP 长时间运行进程(队列、消费者、定时任务、Worker 等)。
Supervisor 本身是一个进程管理工具,主要运行在 Linux/Unix 系统上,用来启动、停止、监控和自动重启后台进程。它采用客户端/服务器模式,由 supervisord 负责管理进程,由 supervisorctl 负责控制。
在 PHP 生态里,它经常和:
- Laravel Queue
- ThinkPHP 队列
- Workerman
- Swoole
- RabbitMQ 消费者
- Redis 队列 Worker
- 自定义 PHP 常驻脚本
一起使用。
为什么 PHP 需要 Supervisor?
PHP 普通请求模式
传统php:
用户请求 | Nginx | PHP-FPM | 执行 PHP | 返回结果 | 进程结束
特点:
- 请求来了才执行
- 执行完销毁
- 不适合长期运行任务
例如:
用户上传 10 万条 Excel 数据:
foreach ($users as $user) {
sendEmail($user);
}
如果同步执行:
请求开始
↓
发送100000封邮件
↓
几十分钟后返回
问题:
- 超时
- 内存爆炸
- 用户等待
- nginx 超时
引入队列 + Supervisor
改成:
用户请求 | 产生任务 | Redis/RabbitMQ | 后台Worker | Supervisor管理 | PHP脚本消费任务
例如:
用户注册:
UserRegister Event ↓ 发送邮件任务 ↓ Redis Queue ↓ queue_worker.php ↓ 发送邮件
Worker 一直运行。
Supervisor 保证:
- Worker 不挂
- 挂了自动启动
- 开机自动启动
- 多进程运行
https://www.49855.net/supervisor/
PHP Worker 示例
1、创建php代码
/data/www/task_worker.php :
<?php
while(true){
echo “worker running\n”;
// 获取任务
$task = getTask();
if($task){
handle($task);
}
sleep(1);
}
特点:这是一个 永不退出的 PHP 程序
运行:
php task_worker.php
它会一直:
worker running
worker running
worker running
2、Supervisor 配置 PHP Worker
创建:
/etc/supervisor/conf.d/task_worker.conf
内容:
[program:task_worker]
command=/usr/bin/php /data/www/task_worker.php
directory=/data/www
autostart=true
autorestart=true
startsecs=5
user=www-data
numprocs=3
redirect_stderr=true
stdout_logfile=/var/log/task_worker.log
逐项解释:
program
名字:
[program:task_worker]
以后:supervisorctl restart task_worker 靠它。
command
执行命令:
command=/usr/bin/php task_worker.php
等价:
php task_worker.php
autostart
自动启动:
autostart=true
Supervisor启动时:
启动worker
autorestart
自动重启:
autorestart=true
例如:
PHP异常:
Fatal error
Process exit
Supervisor:
检测退出
|
重新启动
numprocs
启动几个Worker:
numprocs=3
实际:
task_worker_00
task_worker_01
task_worker_02
三个PHP进程。
3、加载配置
修改配置后:
重新读取:
supervisorctl reread
更新:
supervisorctl update
启动:
supervisorctl start task_worker
查看:
supervisorctl status
PHP Worker 编写注意事项
① 不要让程序退出
错误:
<?php
doTask();
exit;
Supervisor:
启动
↓
退出
↓
重新启动
↓
退出
↓
死循环
日志会爆。
正确:
while(true){
doTask();
sleep(1);
}
② 捕获异常
不要:
throw new Exception();
直接退出。
应该:
while(true){
try{
work();
}catch(Throwable $e){
log($e);
}
}
③ 控制内存
长期运行:
while(true){
process();
}
可能:
100MB
200MB
500MB
OOM
建议:
处理一定数量:
$count=0;
while(true){
process();
$count++;
if($count>1000){
exit;
}
}
Supervisor 会自动重新拉起。