laravel不支持任务级priority参数,队列优先级本质是通过--queue参数控制worker轮询顺序;必须显式指定队列名分发任务,并按urgent,high,default,low严格排序启动命令,database驱动加priority字段易导致漏扫和路由错误。

Laravel 原生不支持任务级 priority 参数,所谓“队列优先级”本质是调度顺序控制问题——不是给单个任务打分,而是决定哪个队列先被 worker 扫描。配错就等于白配,尤其在 database 驱动下容易积压高优任务。
用 --queue 参数控制消费顺序最直接
这是 Laravel 官方机制,worker 每次只检查一个队列,按 --queue 后面的顺序从左到右轮询,前面队列不空就不会往后看。
- 分发时必须显式指定队列名:
dispatch(new NotifyUser())->onQueue('urgent') - 启动命令要严格按优先级排列:
php artisan queue:work --queue=urgent,high,default,low - 别信“默认队列自动降级”这种说法——如果
default排在urgent前面,urgent 任务永远等在后面 - 验证是否生效:往
urgent推一条任务,立刻查日志,handle()必须秒触发,否则说明顺序没生效或队列名拼错
database 驱动加 priority 字段风险极高
很多人想在 jobs 表里加 priority 字段再重写 retrieveNextJob(),但实际线上踩坑最多:
- database 驱动本身是按
id ASC扫表,哪怕你加了ORDER BY priority DESC,在高并发下仍可能漏扫——因为WHERE reserved_at = 0 AND available_at 条件没索引支撑 - 必须给
jobs表加复合索引:ALTER TABLE jobs ADD INDEX idx_queue_priority (queue, priority, reserved_at, available_at),否则查询会全表扫描 - QPS 超过 50 就明显延迟,官方文档其实隐晦提示过:“Don’t use database driver for priority queues in production”
- 如果你非要用,
priority字段类型建议用tinyint(-128 ~ 127),别用enum或字符串,避免排序失效
Redis 多队列 + Supervisor 多进程才是生产首选
真正稳定、可横向扩展的方案,是让每个优先级独占一个 Redis list 键,并用独立 worker 进程监听,互不干扰。
- 不用改任何 Laravel 核心类,只靠配置和部署逻辑就能实现隔离:
redis-cli llen queues:urgent和llen queues:default可分别监控 - Supervisor 配置里为每个队列写独立段,例如:
[program:laravel-worker-urgent]对应command=php artisan queue:work --queue=urgent --sleep=1 -
--sleep=1用于 urgent 队列(快速响应),--sleep=5用于 low 队列(降低 Redis 查询压力) - 注意
numprocs=1,否则同一队列多个 worker 会抢任务,反而破坏优先级语义
最容易被忽略的一点:无论用哪种方案,都必须确保所有任务分发代码统一走 onQueue(),而不是部分用硬编码队列名、部分依赖 config 默认值。线上出问题,90% 是因为某处漏写了 ->onQueue('high'),结果任务悄悄进了 default 队列,还查不出源头。











