Laravel队列任务执行慢的核心问题在于队列驱动未生效、Worker未被supervisor守护、任务内N+1查询、retry_after设置过短及未按优先级分离队列;须验证Redis连接与worker运行状态,优化Eloquent查询,合理配置超时与队列权重,并用Horizon监控定位瓶颈。

检查队列驱动和Worker进程是否真正运行
90% 的“慢”其实是“根本没在跑”。sync 驱动下所有 delay() 无效,任务直接同步阻塞执行;切到 redis 或 database 后若没启动 worker 或 supervisor 配置未重载,任务就一直卡在 pending 状态。
- 确认
QUEUE_CONNECTION=redis(或database)已生效,不是 QUEUE_DRIVER(Laravel 9+ 已弃用) - 运行
php artisan queue:work --once快速验证单次执行是否正常 - 生产环境必须用 supervisor 管理:改完配置后执行
supervisorctl reread && supervisorctl update && supervisorctl restart queue-worker: - 用
php artisan queue:status查看当前 pending / failed 数量,结合redis-cli keys "queues:*"观察 Redis 队列积压情况
优化任务内部的数据库查询
一个 Eloquent N+1 查询或全表扫描,就能拖垮整个 worker 并发吞吐。队列任务的 handle() 是关键路径,必须当作接口性能瓶颈来对待。
- 禁用延迟加载:
Model::withoutEagerLoading()或全局关闭$model->$with = []; - 关联数据一律用
with(['user', 'profile'])预加载,避免循环中查库 - 只取必要字段:
select('id', 'name', 'status'),别用get()拉全量 - 在 where 条件字段上加数据库索引,尤其是
status、created_at、available_at - 高频字典类数据(如国家、状态枚举)用
Cache::rememberForever()缓存,避免每次查表
调整 retry_after 和 block_for 避免假性积压
Redis 队列里任务反复重试、越积越多,大概率是超时设置不合理,导致任务还没执行完就被 Redis 当失败回收,又立刻塞回队头。
-
retry_after 至少设为任务 P95 耗时 + 20%:比如监控显示 95% 的任务在 8 秒内完成,就设
retry_after=30 -
block_for建议设为0或1:避免 worker 空转等待,尤其在高并发下浪费 CPU - 不要依赖无限重试,定期执行
php artisan queue:failed清理死信,配合--force删除确定失败的任务
按优先级拆分队列并控制消费权重
Laravel 不支持单队列内动态排序,但混合投递 urgent 订单通知和 default 日志归档,必然导致高优任务被堵住。
- 在任务类中声明
public $queue = 'urgent';,或分发时写dispatch(new PayJob())->onQueue('urgent'); - 启动两个独立 worker:
php artisan queue:work --queue=urgent --max-jobs=50和php artisan queue:work --queue=default --max-jobs=200 - 用 Horizon 监控各队列耗时、失败率和吞吐量,定位哪个队列成了瓶颈


















