Laravel 8 循环中Bus::chain队列任务链执行顺序异常如何解决?
问题根因
你当前的写法是循环两次分别派发了两个独立的任务链,每个链对应一个model的两个任务。如果你的队列配置了多个工作进程,多个进程会并行拉取不同链的任务执行:进程1拉取第一个链的getRecommendations(1)执行时,进程2会同时拉取第二个链的getRecommendations(2)执行,所以才会出现两个get任务先执行完成,再执行两个process任务的情况。如果你的队列仅配置1个工作进程,默认先进先出规则下你的原有代码是可以跑出预期顺序的。
解决方案
根据你的业务需求可以选择以下两种方案:
方案1:严格要求所有任务按 getRecommendations(1)→processRecommendations(1)→getRecommendations(2)→processRecommendations(2) 完全串行执行
直接把所有任务按预期顺序拼接为同一个任务链一次性派发即可,不管配置多少个工作进程,任务都会严格按顺序执行:
// 按预期顺序拼接任务数组 $taskList = []; foreach ([1, 2] as $model) { $taskList[] = new getRecommendations($model); $taskList[] = new processRecommendations($model); } // 一次性派发整个任务链 Bus::chain($taskList)->dispatch();
方案2:允许不同model的任务并行,仅保证同一个model的get任务完成后再执行对应process任务
如果后续扩展model数量时希望提升处理性能,不需要完全串行所有任务,可以给每个model的任务分配独立专属队列,且配置每个专属队列的工作进程数为1,即可保证同model任务串行、不同model任务并行:
$models = [1, 2]; foreach($models as $model) { Bus::chain([ (new getRecommendations($model))->onQueue('recommend_model_' . $model), (new processRecommendations($model))->onQueue('recommend_model_' . $model), ])->dispatch(); }
启动队列进程时,如果用原生队列命令,可为每个队列单独启动1个进程:
# 启动model 1的队列进程 php artisan queue:work --queue=recommend_model_1 # 启动model 2的队列进程 php artisan queue:work --queue=recommend_model_2
如果使用Horizon管理队列,在配置文件中将对应队列的processes参数设置为1即可。
小提示:Laravel规范中类名建议使用大驼峰命名,将
getRecommendations改为GetRecommendations、processRecommendations改为ProcessRecommendations会更符合框架开发规范,不影响现有功能运行。
内容的提问来源于stack exchange,提问作者Renie
相关产品推荐
相关产品推荐

