Laravel队列任务失败后不重试,必须同时设置tries和backoff;tries=0或未定义则禁用重试,backoff失效;数组式backoff支持递增延迟,长度需≥tries−1;retryAfter()优先级高于backoff;sync驱动不支持重试,需改用redis或database。

队列任务失败后不重试?检查 backoff 和 tries 是否同时设置
默认情况下,Laravel 队列任务失败后不会自动重试——哪怕你写了 backoff。必须显式声明 tries,否则框架直接标记为 failed,跳过所有退避逻辑。
常见错误现象:App\Jobs\SendNotification 报错后立刻进 failed_jobs 表,日志里完全看不到延迟重试痕迹。
-
tries = 0或未定义 → 等同于禁用重试,backoff彻底失效 -
tries = 3且backoff = 60→ 第一次失败后等 60 秒重试,第二次再等 60 秒,第三次失败才进 failed_jobs - 若用数组形式
backoff = [1, 5, 60],则每次重试等待时间递增,对应第 1/2/3 次失败
想让第 2 次失败后延迟更久?用数组式 backoff 而不是固定值
固定数字的 backoff(如 public $backoff = 10;)对所有重试都用同一秒数,不适合网络抖动、临时限流这类需要“越拖越久”的场景。
使用场景:调第三方 API 时,第一次失败可能是瞬时超时,第二次可能是对方限流,第三次就得等更久再试。
- 写成
public $backoff = [3, 15, 120];,表示第 1 次重试前等 3 秒,第 2 次等 15 秒,第 3 次等 120 秒 - 数组长度必须 ≥
tries - 1,否则 Laravel 会 fallback 到最后一个值(比如tries=5但backoff=[1,2],第 3/4 次重试都用 2 秒) - 注意:这个数组只控制“重试间隔”,不改变任务入队时间;底层仍依赖
delay()或retryAfter()实现
Redis 队列下 retryAfter 和 backoff 冲突?优先级关系要理清
在 Redis 驱动中,如果 job 类同时定义了 retryAfter() 方法和 $backoff 属性,retryAfter() 会完全覆盖 backoff —— 连数组形式都不生效。
性能影响:每次重试都重新计算 retryAfter() 返回值,比静态 $backoff 多一次 PHP 方法调用,但可忽略不计;真正要注意的是语义混淆。
-
retryAfter()是每个重试周期的绝对延迟秒数(从当前时刻起算),返回整数即可 -
$backoff是相对间隔,只在tries > 1时参与调度,且仅用于database和redis(部分旧版不支持数组) - 二者不要混用;选一个,明确写在 job 类里,避免后期有人改了
backoff却发现没效果
本地开发用 sync 驱动测试不到重试?换 redis 或 database
sync 驱动是同步执行,失败就抛异常,根本不会走重试流程——它连队列都绕过了。所以你在 .env 里设了 QUEUE_CONNECTION=sync,再怎么配 backoff 都白搭。
兼容性影响:SQLite 的 database 驱动在高并发下可能丢任务,生产环境务必用 redis 或 database(配合 MySQL/PostgreSQL)。
- 开发时快速验证:改
.env为QUEUE_CONNECTION=redis,确保REDIS_HOST可达 - 用
php artisan queue:work --stop-when-empty手动触发一次 worker,观察日志里是否有Processing→Failed→Processing循环 - 别信
php artisan queue:listen,它已废弃,行为不稳定
真正容易被忽略的是:重试次数和延迟策略生效的前提,是任务没在 handle() 里 catch 所有异常。只要抛出未捕获异常,Laravel 才介入重试;如果自己 try-catch 吞掉错误又不手动 fail(),那什么配置都没用。











