thinkphp队列平滑重启需监听sigterm:tp6.1+启用--daemon与--stop-when-empty,supervisor设stopwaitsecs≥30,redis.retry_after须≥任务最长执行时间且≥stopwaitsecs,确保任务不丢失、不重复。

Supervisor 重启时队列进程被强制 kill 导致任务丢失
ThinkPHP 的 queue:work 进程默认不响应 SIGTERM,Supervisor 发送 stopsignal 后等几秒就直接 SIGKILL,未处理完的任务直接中断。这不是 ThinkPHP 的 bug,是它默认没实现优雅退出信号监听。
解决核心:让 queue:work 主动监听 SIGTERM,收到后完成当前任务再退出。TP6.1+ 已内置支持,但需显式启用:
- 启动命令必须加
--stop-when-empty或配合--max-jobs控制单次执行上限(避免无限卡住) - 确保使用
php think queue:work --daemon(注意是--daemon,不是--once) - Supervisor 配置里
stopwaitsecs建议设为 30+,给足时间收尾 - 若用 Redis 驱动,确认
retry_after和block_for设置合理,避免任务被重复投递
Supervisor reload 不触发 queue 进程重启的常见原因
改了 Supervisor 配置后 supervisorctl reload,发现 queue:work 进程没拉起——大概率是配置中漏了 autostart=true 或 autorestart=true,或者程序启动失败被静默忽略。
检查要点:
-
command路径必须写绝对路径,比如/usr/bin/php /var/www/tp6/think queue:work --daemon,不能用~/或相对路径 -
directory必须指向项目根目录(即有think文件的那层),否则加载器找不到类 - 日志里出现
ERROR (no such process)或STARTING → FATAL,先看stderr_logfile输出,90% 是 PHP 扩展缺失或 .env 读取失败 - 别依赖
environment=PATH="/usr/bin"来补全命令,command里该写的路径一个都不能少
ThinkPHP 队列平滑重启时如何避免重复消费
Supervisor stop → start 间隙,如果 Redis 中的 job 还在 reserve 状态(没被 ack),且 retry_after 时间太短,可能被其他 worker 重复捞取。这不是并发问题,是生命周期管理错位。
关键参数要对齐:
-
config/queue.php中redis.retry_after(单位秒)必须 ≥ 单个任务最长执行时间 + 网络/IO 波动余量 -
supervisor.conf的stopwaitsecs必须 ≤retry_after,否则还没停完就被 Redis 当超时重发 - 避免在任务里做阻塞操作(如
sleep(60)),ThinkPHP 不会主动中断正在运行的 handle(),得靠超时机制兜底 - 上线新版本前,建议先
php think queue:restart清除旧的 queue:work 进程状态缓存(尤其 TP6.0.x)
为什么 supervisorctl restart xxx 总是卡住或失败
直接执行 supervisorctl restart queue_worker 容易卡在 STOPPING,本质是进程没响应 SIGTERM,Supervisor 只能等超时后强杀。这不是网络或权限问题,是信号链路没打通。
更稳的做法:
- 先
supervisorctl stop queue_worker,观察日志是否输出「Stopping worker...」类提示(TP6.1+ 有该日志) - 若无响应,检查是否启用了
--daemon模式 ——--once模式下根本不会长期运行,无法监听信号 - 确认没有在代码里调用
pcntl_signal_dispatch()或pcntl_signal()干扰默认行为(TP 内部已封装) - Linux kernel 版本低于 3.15 时,某些容器环境对
stopwaitsecs行为异常,建议升级或换用 systemd
真正麻烦的从来不是重启命令怎么写,而是 Redis 里那个还没 ack 的 job 到底算成功还是失败——得看你 retry_after、任务幂等性、以及有没有在 finally 里补 log。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










