laravel队列不执行多因进程异常或配置错误:需检查supervisor状态并重载配置,确认QUEUE_CONNECTION生效,避免handle中阻塞操作,合理设置retry_after与block_for,按驱动特性控制并发,并监控耗时优化。

队列任务卡住不执行?先查 supervisor 和 php artisan queue:work 状态
Laravel 队列不跑,90% 不是代码问题,而是进程没起来或崩了。运行 php artisan queue:work 是临时调试手段,但生产环境必须靠 supervisor 持续拉起。常见错误是改了配置却没重载 supervisor:改完 supervisord.conf 后必须执行 supervisorctl reread + supervisorctl update + supervisorctl restart queue-worker:。
另一个高频坑:本地用 sync 驱动测试没问题,切到 redis 或 database 后任务进队列但不消费——大概率是 QUEUE_CONNECTION 环境变量没生效,或者 .env 里写成了 QUEUE_DRIVER(Laravel 9+ 已弃用,只认 QUEUE_CONNECTION)。
handle() 方法里别做阻塞操作,尤其 sleep()、file_get_contents()、未设超时的 http 请求
队列任务默认有 60 秒超时(timeout 属性),但更危险的是隐式阻塞:比如调用一个没设 timeout 的 Guzzle 请求,外部 API 卡住 3 分钟,整个 worker 进程就挂死,后续所有任务排队等它。
- HTTP 请求一律加
timeout和connect_timeout,Guzzle 推荐用['timeout' => 10, 'connect_timeout' => 5] - 文件读写优先用流式处理,避免
file_get_contents()一次性加载大文件到内存 - 绝对不要在
handle()里写sleep(30)做轮询——改用延迟队列:dispatch((new YourJob())->delay(now()->addSeconds(30))) - 数据库慢查询要加索引,否则单个任务执行太久,worker 并发数再高也救不了吞吐量
Redis 队列爆满?检查 retry_after 和 block_for 配置冲突
Redis 驱动下任务反复重试、堆积如山,常因 retry_after(任务最大执行时间)设得太短,而实际任务偶尔会超时;一旦超时,Redis 就把任务扔回队列头,造成“假性积压”。更隐蔽的问题是 block_for(空闲时等待时间)和 retry_after 配合不当:若 block_for=5 但 retry_after=10,worker 可能刚取任务就因网络抖动延迟,还没开始处理就被 Redis 当作失败回收。
建议值:
-
retry_after至少比任务 P95 耗时多留 20%,比如监控显示多数任务 8 秒完成,就设30 -
block_for设为0(不阻塞)或1(最多等 1 秒),避免空转浪费 CPU - 用
php artisan queue:failed定期清理死信,别依赖自动重试无限循环
需要并发控制?别硬改 --concurrent,先看驱动是否支持
php artisan queue:work --concurrent=10 看似能提并发,但仅对 redis 和 sqs 有效;database 驱动根本不支持并发消费,强行加参数只会启动 10 个进程抢同一条记录,大量锁表和失败重试。
真正可控的并发方式:
- Redis:用
--concurrent+--max-jobs限流,防内存溢出 - Database:按业务拆分多个队列名(如
emails、notifications),再为每个起独立 worker,用QUEUE_CONNECTION=database QUEUE=emails php artisan queue:work - 所有驱动都建议配
--memory=128,防止长任务吃光内存后被系统 OOM kill
最易被忽略的一点:队列优化不是调参游戏,得先用 Telescope 或日志统计任务耗时分布,否则所有“优化”都在拍脑袋。