根本原因是 Laravel queue:work 在 --daemon 模式下内存缓慢增长、异常未捕获或信号处理不完整导致静默崩溃;需正确配置 Supervisor 的 stopwaitsecs=30、killasgroup=true、stopasgroup=true,并部署后执行 queue:restart。

为什么 queue:work 进程会意外退出
根本原因不是代码报错,而是 Laravel 的 queue:work 在 --daemon 模式下长期运行时内存缓慢增长、异常未捕获、或信号处理不完整导致的静默崩溃。常见现象包括:日志突然中断、ps aux | grep queue:work 查不到进程、但 Supervisor 状态显示 RUNNING(其实是假死)。这和 queue:listen(已废弃)不同,后者每次任务都 reload 代码,天然抗内存泄漏,但性能差、不支持现代队列特性。
Supervisor 配置必须设对的三个关键参数
只写 autostart=true 和 autorestart=true 不够,以下三项缺一不可:
-
stopwaitsecs=30:给queue:work足够时间完成当前任务并响应queue:restart信号,否则会被 SIGKILL 强杀,丢失正在处理的任务 -
killasgroup=true和stopasgroup=true:确保子进程(如 PHP 的 pcntl_fork 子进程、Redis 连接等)一并终止,避免残留连接占满 Redis maxclients -
startsecs=5:要求进程启动后稳定运行满 5 秒才视为“成功启动”,防止因配置错误(如.env中QUEUE_CONNECTION=redis但REDIS_HOST错误)导致 Supervisor 反复拉起又崩溃
部署后必须执行 queue:restart,不能只靠 Supervisor 自动拉起
Supervisor 的 autorestart 只解决进程崩溃,不解决代码更新问题。若你改了任务逻辑但没触发重启信号,旧进程仍用老代码跑新任务——这就是“任务执行结果和代码对不上”的根源。
- 每次部署脚本末尾加一行:
php artisan queue:restart - 验证信号是否生效:
php artisan tinker→ 输入Cache::get('laravel_queue_restart_signal'),返回时间戳即成功 - 注意缓存驱动必须是跨进程共享的(
redis或file),array驱动会导致信号写入后其他进程读不到
多个队列共存时别用 numprocs=8 这种偷懒写法
一个 [program] 块配 numprocs=8 并监听 --queue=default,看似省事,实则埋雷:8 个进程争抢同一张 jobs 表或同一个 Redis list,高并发下容易出现任务重复消费(尤其 database 驱动)、Redis 连接耗尽、或 SELECT FOR UPDATE 锁等待超时。
- 按业务拆队列:比如邮件发信走
emails,报表生成走reports - 每个队列单独配一个
[program]块,command中显式写死--queue=emails - Redis 驱动下,所有
numprocs总和建议 ≤15(假设redis.conf中maxclients=200)


















