重试执行失败的队列任务


失败队列任务重试

Laravel 消息队列支持对执行失败的任务进行重试(详见 Laravel 队列文档处理失败的任务部分),执行失败的任务会被存储在 failed_jobs 数据表中,你需要运行如下 Artisan 命令创建这张数据表:

php artisan queue:failed-table
php artisan migrate

其表结构如下所示:

其中包含了队列驱动、队列名称、以及序列化的任务类实例,通过这些信息可以反序列化出队列任务进行重试。

你可以运行 queue:retry 命令通过指定任务 ID 来重试对应的队列任务(ID 放置在命令最后,ID 值就是 failed_jobs 数据表对应记录的 id 字段值):

php artisan queue:retry 300

指定最大尝试次数

但是这样太被动了,也不方便运维,取而代之的,你可以在启动队列处理器进程时通过 --tries 参数指定是否对失败任务进行重试,以及最大尝试次数(含第一次运行,所以真正的重试次数等于该参数值减一):

php artisan queue:work --tries=3

失败重试的底层原理也很简单,就是将失败任务重新推送到队列,在下次被轮询到时再执行一次,不过每执行一次会更新任务实例的 attempts 字段值,如果已经超过 --tries 指定的次数,则将其丢弃,不再重试。

此外,还可以在任务类中通过设置 tries 属性值来指定最大尝试次数:

这样一来,就不用在队列处理器启动命令中手动设置 tries 参数了,Laravel 会自动基于这个配置对失败任务进行重试:

 php artisan queue:work

这样做的另一个好处是可以为不同的队列任务设置不同的尝试次数,更加灵活:

需要注意的是,如果在任务类和 Artisan 命令中都设置了最大尝试次数,那么任务类中的 tries 属性值会覆盖命令行中的 tries 参数值。

延迟重试

如果消息队列负载很高,可以延迟失败任务的重试,避免某个反复失败的任务占用过多的系统资源,阻塞后续其他正常队列任务推送到消息队列执行。这可以通过在任务类设置 backoff 属性来实现:

或者在 Artisan 命令中设置 --backoff 参数:

php artisan queue:work redis --tries=3 --backoff=60

以上两种实现功效一样,都是表示队列任务执行失败后,延迟 60 秒推送到消息队列重试,基本用法和优先级和最大尝试次数一样,不再赘述。

Laravel 8.0 之前对应的属性值是 retryAfter,命令行参数也不是 --backoff,而是 --delay,这一点在使用更早版本的 Laravel 时需要注意下。

跳跃式延迟

不过某些耗时任务 60 秒可能还没有执行完成,可以每次重试后在上一次基础上延长延迟时间实现「跳跃式」延迟:

以上配置的含义是第一次重试延迟 60 秒,第二次重试延迟 120 秒:

同理,你也可以通过在 Artisan 命令中通过 backoff 参数设置「跳跃式延迟」:

php artisan queue:work --backoff=60,120

如果最大尝试次数超过 backoff 配置的数量,则后续重试以最后一个延迟时间值为准,所以,如果这里的最大尝试次数配置为 5,则后面的重试延迟时间都是 120 秒。当然,你也可以为 backoff 配置更多的延迟时间跳跃值。


点赞 取消点赞 收藏 取消收藏

<< 上一篇: 队列优先级

>> 下一篇: 自动取消已放弃的订单