必须显式设 $tries,否则 phpredis 连接异常(如 Connection refused)不会重试而直接进 failed_jobs;任务类需设 public $tries = 3,并在 handle() 中 try/catch RedisException,按错误类型手动 delay() 或 throw。

必须显式设 $tries,否则 phpredis 抛出的连接异常(如 RedisException: Connection refused)根本不会重试,直接进 failed_jobs 表。
为什么 phpredis 异常默认不重试
Laravel 队列重试机制完全不感知底层驱动异常类型。哪怕 phpredis 报 Connection refused 或 NOAUTH Authentication required,只要任务类没定义 $tries,框架就当“一次性任务”处理——抛异常 → 写表 → 结束。
-
$tries是开关,不是可选项:未定义、为null或0,等同于禁用重试 -
phpredis的异常(RedisException)和其他 PHP 异常一样,需靠$tries触发框架级重试流程 - 不设
$tries却在failed()里手动dispatch(),会绕过原始任务上下文,丢失 job ID 和中间件链路
怎么让 RedisException 真正重试
核心是两层控制:框架兜底 + 业务分流。不能只靠 $tries 撑住所有 Redis 故障。
- 任务类必须设
public $tries = 3;,这是触发重试的前提 - 在
handle()中try/catch捕获RedisException,区分场景:
– 若是Connection refused或Failed to connect,说明 Redis 服务宕机或网络不通,立即dispatch($this)->delay(now()->addSeconds(2)),避免等默认退避(1s→2s→4s)
– 若是NOAUTH或READONLY,属于配置错误,不该重试,直接throw $e进failed_jobs - 删掉
$backoff数组:它对RedisException无意义,因为连接失败时连退避逻辑都走不到;靠catch后手动delay()更精准
retryUntil() 对 Redis 连接异常有用吗
基本没用。因为 retryUntil() 判断的是“任务执行是否超时”,而 RedisException 往往在命令发起瞬间就抛出(毫秒级),根本不会耗到你设的时间点。
立即学习“PHP免费学习笔记(深入)”;
-
retryUntil(now()->addSeconds(15))只对“连接成功但命令执行慢”有效,比如BLPOP阻塞等待超时 - 对
Connection refused这类底层连接失败,retryUntil()不生效,仍依赖$tries+ 手动delay() - 混用
$tries = 3和retryUntil()时,后者优先级更高,但对连接异常无实际影响
生产环境必须同步检查的 Redis 配置项
重试再准,连不上 Redis 也是白搭。以下三项漏一个,RedisException 就会高频出现:
-
.env中确认REDIS_HOST、REDIS_PORT、REDIS_PASSWORD与实际 Redis 服务一致(比如端口被改成6999却没改配置) -
config/database.php的redis.default下,database值不能为0(避免和 Horizon 或 session 冲突),建议显式设为env('REDIS_DB', 2) - 运行
redis-cli -h $REDIS_HOST -p $REDIS_PORT ping,必须返回PONG;若报NOAUTH,说明REDIS_PASSWORD没配对或 Redis 服务端 requirepass 未生效
真正容易被忽略的是:phpredis 异常重试不是开个开关就能自动适配的,它要求你既得让框架知道“要重试”,又得在代码里判断“这次该等多久再试”。靠 $tries 走完三次默认退避,不如在 catch 里用 delay() 主动控节奏——尤其是连接类异常,恢复窗口往往就几秒。



















