Laravel database队列如何实现superlow队列单实例仅单任务运行
解决方案
你可以根据你的Laravel版本和运维部署习惯,从以下3种可行方案中选择:
方案1:拆分独立worker(推荐,无代码改动,性能最优)
- 把原有多实例部署的通用worker启动命令改回原来的配置,去掉superlow队列:
这部分worker可以继续正常水平扩展,不影响高优队列的处理效率。php artisan queue:work --queue=high,default,low - 单独部署仅处理superlow队列的worker,启动命令如下:
运维侧控制该worker全局仅启动1个实例即可:php artisan queue:work --queue=superlow- 用Supervisor管理的话,配置里直接设置
numprocs=1 - 不要在多台服务器上同时启动该专用worker,若需要高可用,可以加一层分布式锁保证同一时间只有一个该类型worker处于运行状态。
- 用Supervisor管理的话,配置里直接设置
方案2:配置队列最大并发(无业务代码改动,需版本支持)
如果你的Laravel版本 >= 8.69.0,直接修改config/queue.php中database驱动的配置,给superlow队列设置并发限制为1:
'database' => [ 'driver' => 'database', 'table' => 'jobs', 'queue' => 'default', 'retry_after' => 90, // 新增以下配置 'max_concurrent_jobs' => [ 'superlow' => 1, ], ],
配置生效后,不管你启动多少个worker,系统会自动保证superlow队列同一时间最多只有1个任务在执行,不会出现抢占问题。
方案3:任务加全局独占锁(兼容性最强,适配所有Laravel版本)
如果你的版本不支持方案2,也不想调整worker部署规则,给所有投递到superlow队列的任务类加上WithoutOverlapping中间件,所有任务共用同一个全局锁:
// 你的superlow队列对应的任务类 class YourSuperLowJob implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; // 定义任务中间件 public function middleware() { return [ (new \Illuminate\Queue\Middleware\WithoutOverlapping('superlow_queue_global_lock')) ->expiresAfter(3600) // 锁过期时间按你任务最长执行时间设置,要大于任务最大耗时 ->releaseAfter(10), // 抢不到锁时,10秒后再放回队列重试 ]; } // 其他业务逻辑 }
该方案通过锁机制保证同一时间只有1个superlow队列的任务能拿到执行权限,其他任务会自动延迟重试。
内容的提问来源于stack exchange,提问作者user3841429
相关产品推荐
相关产品推荐

