You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel多节点部署时运行中Redis队列任务被其他服务器拾取失败如何解决

问题根因
  1. 队列启动命令未匹配自定义连接配置
    你配置了retry_after为86400秒的product-import自定义队列连接,但启动队列的命令php artisan queue:listen --queue=product-import --memory=3G --timeout=0仅指定了队列名称,没有指定使用product-import连接,默认会调用全局配置的default连接,而默认连接的retry_after通常为90秒。任务运行满90秒后,系统会判定该worker已经死亡,将任务重新推回待执行队列,因此被第二台节点拾取。
  2. ShouldBeUnique接口作用范围不匹配
    ShouldBeUnique仅限制任务入队阶段的唯一性,同一个uniqueId的任务无法重复进入待执行队列,但当任务被worker取出到预留队列开始执行时,该唯一性锁就会自动释放,无法避免同一个任务被多个节点同时执行的场景。
  3. 运行时去重中间件未启用
    你注释了WithoutOverlapping中间件,该中间件才是用于限制同一个任务同时仅能有一个运行实例的工具,缺失该防护导致重复执行的任务可以正常启动。
解决方案
  • 修正队列启动命令,优先使用性能更高的queue:work替代queue:listen,同时显式指定使用自定义连接:
php artisan queue:work --connection=product-import --queue=product-import --memory=3G --timeout=0
  • 修正队列连接配置中的队列名,避免和实际使用的队列名不匹配:
'product-import' => [
    'driver' => 'redis',
    'connection' => 'default',
    'queue' => 'product-import', // 固定为实际使用的队列名,或对应调整ENV变量值
    'retry_after' => 86400,
    'block_for' => 10,
    'timeout' => 86400
],
  • 恢复WithoutOverlapping中间件作为双重防护,设置和任务最大运行时长匹配的锁过期时间:
public function middleware()
{
    return [new WithoutOverlapping($this->Import->cms->id)->expireAfter(86400)];
}
  • 可选配置:如果该任务不需要重试,直接在任务类中添加public $tries = 1;,避免任务异常后重复执行。

内容的提问来源于stack exchange,提问作者Gordon Freeman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 16:45:03