当前位置:首页 > 文章列表 > 文章 > php教程 > Laravel 队列重试次数怎样与失败记录配合

Laravel 队列重试次数怎样与失败记录配合

来源:17golang原创 2026-11-12 00:26:55 0浏览 收藏

Laravel 队列重试次数怎样与失败记录配合

Laravel 队列的重试次数和失败记录不是两个独立开关:worker 或作业类先决定一个作业最多尝试多少次,异常、超时以及某些中间件或手动 release() 都可能消耗尝试;只有作业耗尽允许的尝试后,才会进入失败作业存储。官方队列文档地址:https://laravel.com/docs/12.x/queues

可以把处理过程记成“尝试 → 退避 → 再尝试 → 达到边界后记录失败”。先把暂时性故障和永久性故障分开,再决定是否用 queue:retry 重新投递,不要看到 failed_jobs 就无条件批量重试。
  • 最大尝试次数:由 queue:work --tries 或作业类的 $tries、tries() 决定。
  • 失败记录时机:作业耗尽尝试、持续超时或最终抛出异常后,才写入 failed_jobs。
  • 重试等待:用 worker 的 --backoff 或作业的 $backoff/backoff() 拉开间隔。
  • 人工动作:先用 queue:failed 查看失败上下文,修复原因后再按 ID 执行 queue:retry。

先区分一次尝试和一条失败记录

worker 从队列取出作业并执行一次,就产生一次尝试。Laravel 文档还特别说明,未处理异常、手动释放、WithoutOverlapping 或 RateLimited 等中间件释放,以及超时,都可能消耗尝试次数。因此“handle() 完整执行过几次”和“attempts 计数是多少”不能简单画等号。

Laravel 队列作业从尝试次数到 failed_jobs 失败记录的静态关系说明图
图1:Laravel 队列尝试、达到上限和失败记录之间的静态说明图,不是运行截图。

如果作业仍有剩余尝试,异常通常会让它回到队列;达到最大尝试后,Laravel 才把它视为 failed job。失败记录保存的是后续人工判断所需的线索,例如作业 ID、连接、队列、失败时间和异常信息,而不是“自动修复已经完成”的证明。

用 worker 和作业类设定重试上限

最粗粒度的配置是在启动 worker 时指定 --tries。如果某个作业需要自己的边界,可以在作业类中声明 $tries 或提供 tries() 方法。作业类的配置适合表达业务差异,例如发送通知和生成报表可能不应该共享同一个重试上限。

# worker 默认最多尝试 3 次,所有未单独声明的作业沿用这个边界
php artisan queue:work redis --tries=3

# 只查看失败作业的 ID、连接、队列和失败时间,先收集上下文再处理
php artisan queue:failed
sync($this->invoiceId);
    }

    public function __construct(private readonly int $invoiceId)
    {
        // 只保存可序列化的标识,处理时重新读取最新业务数据。
    }
}
?>

如果同时设置 worker 的 --tries=3 和作业类的 $tries=5,应以作业类规则作为该作业的细粒度配置。不要把 --tries=0 当成“失败自动解决”;官方文档将它定义为无限重试,只有确定故障可以最终恢复时才适合采用。

用 backoff、retryUntil 和 timeout 拉开边界

默认情况下,异常后的作业可能立即重新入队。依赖外部 API、数据库或限流服务时,紧密重试会进一步放大故障。可以用 worker 的 --backoff 或作业类的 backoff 属性/方法设置等待时间,也可以返回一组等待秒数形成逐步退避。

addMinutes(10);
    }
}
?>

retryUntil() 用时间边界控制重试时段;如果它和 tries 同时存在,Laravel 文档说明优先使用时间边界。另一个容易混淆的参数是 worker 的 --timeout:它限制单次执行时长,而不是等待下一次重试的时长。队列连接的 retry_after 也要和 timeout 配合,通常应让 timeout 比 retry_after 短几秒,避免冻结作业被重复处理。

Laravel worker tries、作业 tries、retryUntil 和 backoff 共同影响失败处理的静态结构图
图2:Laravel 队列重试控制项与继续尝试或写入失败记录的静态结构图,不是运行截图。

达到上限后怎样阅读 failed_jobs

新应用通常已经包含失败作业表迁移;如果项目没有,可以先生成失败作业表迁移并执行迁移。正式环境中,先确认失败存储没有被显式关闭,再用命令查看记录:

# 没有失败作业表时生成迁移,然后按项目流程执行数据库迁移
php artisan make:queue-failed-table
php artisan migrate

# 查看失败作业,记录目标 ID 和异常原因
php artisan queue:failed

# 只对已经修复原因的指定作业重新投递,避免无差别重试全部记录
php artisan queue:retry ce7bb17c-cdd8-41f0-a638-9b4fef4e5ece

失败记录代表一次处理链路已经到达边界,不代表下一次 queue:retry 一定成功。若异常来自错误参数、已删除资源或不具备幂等性的外部副作用,应先修复代码或数据,再选择指定 ID 重试。批量重试适合有明确共同根因且已经修复的记录;否则容易让同一种错误再次制造大量失败。

把最终失败处理和幂等性收口

作业可以定义 failed(?Throwable $exception),在最终失败时发送通知、更新业务状态或留下可检索的关联 ID。要注意,Laravel 会在调用 failed 前重新实例化作业,handle 中临时修改过的属性不会可靠地带到失败回调,因此关键上下文应落在持久化记录或结构化日志中。

exportOnce($this->reportId);
    }

    public function failed(?Throwable $exception): void
    {
        // 最终失败只做通知和状态收口,不在这里再次 dispatch 自己。
        app(FailureNotifier::class)->notify($this->reportId, $exception);
    }
}
?>

如果作业通过中间件限流、避免重叠或手动释放来等待资源,要把这些释放也算进尝试预算;必要时增加 $tries,同时给出合理的 backoff。对于连续抛出异常的第三方依赖,还可以使用 Laravel 的异常节流中间件,把“允许多少次异常”和“进入节流后等待多久”分开设计。

现象先看什么下一步
作业瞬间重复执行backoff、异常类型和 worker 参数增加退避,确认瞬时故障不会触发紧密重试
作业很快进入 failed_jobs$tries、retryUntil、timeout 与释放次数重新计算尝试预算,不要只把上限改成无限
retry 后仍然失败失败记录中的异常和业务数据先修复根因与幂等性,再重试指定 ID
同一订单被处理多次外部副作用是否有幂等键让成功写入和重试判断可以安全重复执行

常见问题

Laravel 队列默认会重试几次?

如果 worker 没有设置 --tries,且作业类也没有自己的尝试配置,官方文档说明作业通常只尝试一次。使用中间件释放或手动 release() 时,应明确增加尝试预算。

失败记录是不是每次异常都会新增一条?

不是。还有剩余尝试时,作业会重新进入队列;耗尽允许的尝试后才会作为 failed job 保存。最终异常可能是业务异常,也可能是 MaxAttemptsExceededException 或超时异常。

可以直接执行 queue:retry all 吗?

可以执行,但应先确认所有失败记录的共同根因已经修复,并且作业具备幂等性。只想验证一个修复时,优先按具体失败 ID 重试。

清理失败记录会重新执行作业吗?

不会。queue:forget 或 queue:flush 只删除失败记录;需要重新投递时使用 queue:retry,需要清理历史数据时再使用忘记或清空命令。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Composer platform check 怎样发现 PHP 版本不兼容Composer platform check 怎样发现 PHP 版本不兼容
上一篇
Composer platform check 怎样发现 PHP 版本不兼容
Laravel Eloquent cursor 怎样处理大结果集
下一篇
Laravel Eloquent cursor 怎样处理大结果集
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    986次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    991次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    1112次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    1083次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    928次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码