必须用物理隔离的独立 worker 进程处理不同优先级队列:高优任务硬编码 onqueue('high'),低优 onqueue('low');为 each 队列启动单独 queue:work 进程;redis 下验证 queues:high/low 键存在;database 驱动需加复合索引 idx_queue_available;horizon 中禁用 auto balance,改用 manual 分配。

在 Laravel 生产环境中确保支付通知、短信发送等高优任务秒级响应,而不是被日志归档、邮件推送等低耗时任务阻塞,必须放弃单 worker 轮询多队列的幻觉,用物理隔离的消费路径兑现优先级承诺。
分发任务时显式指定队列名
所有高优任务必须调用 onQueue() 显式进入命名队列,不能依赖默认队列或动态拼接队列名——【队列名必须是硬编码字符串,如 'high'、'urgent',不可来自变量或配置项】。
dispatch(new SendSms($phone))->onQueue('high');
dispatch(new ProcessLogArchive())->onQueue('low');
这一步不执行,后续所有配置都失效。Laravel 不识别 priority=5 这类参数,只认 queue 字段值。
为每个优先级启动独立 queue:work 进程
这是生产环境唯一可靠方案。共用一个进程监听 high,default,low 会导致 default 中一个 30 秒的任务直接卡住 high 队列 30 秒。
方法一:手动验证(仅限测试)
php artisan queue:work --queue=high --sleep=1 --max-jobs=1000 --timeout=60
php artisan queue:work --queue=low --sleep=10 --max-jobs=200 --timeout=300
方法二:Supervisor 管理(生产必需)
① 创建 [program:laravel-worker-high] 段,command 值为:
php artisan queue:work --queue=high --sleep=1 --max-jobs=1000 --timeout=60
② 创建 [program:laravel-worker-low] 段,command 值为:
php artisan queue:work --queue=low --sleep=10 --max-jobs=200 --timeout=300
③ 【numprocs 必须设为 1,否则同一队列多个 worker 会抢任务,破坏优先级语义】
④ 执行 sudo supervisorctl reread && sudo supervisorctl update && sudo supervisorctl start all
Redis 驱动下验证队列长度是否真实隔离
别只看日志,直接查 Redis 键值。每个队列名对应独立 list 键:queues:high、queues:low。
redis-cli llen queues:high
redis-cli llen queues:low
如果 high 队列有积压但 handle() 未触发,说明 high 进程已崩溃或未启动——Supervisor 的 autostart=true 和 startsecs=0 必须启用。
Database 驱动必须加复合索引,否则必积压
database 驱动所有队列共享 jobs 表,靠 queue 字段区分。若不加索引,WHERE queue = 'high' 查询会全表扫描。
执行 SQL:
ALTER TABLE jobs ADD INDEX idx_queue_available (queue, available_at, reserved_at);
这个索引覆盖了 Laravel 默认查询的三个关键字段。不加它,QPS 超过 50 就明显延迟,【官方文档隐晦提示:“Don’t use database driver for priority queues in production”】。
Horizon 中禁用 auto balance,改用 manual 分配
Horizon 默认 balance=auto 会把所有队列混在一起调度,彻底废掉优先级。必须强制关闭。
编辑 config/horizon.php:
'supervisors' => [
'production' => [
'balance' => 'false',
'processes' => 1,
'environments' => ['production'],
],
],
再为每个队列单独定义 supervisor 段:
'high' => ['connection' => 'redis', 'queue' => ['high'], 'balance' => 'false'],
'low' => ['connection' => 'redis', 'queue' => ['low'], 'balance' => 'false']











