使用Guava Retrying优雅的实现业务异常重试

2024-01-11 06:52

本文主要是介绍使用Guava Retrying优雅的实现业务异常重试,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

上次写过一篇如何使用spring retry来实现业务重试的文章:https://blog.csdn.net/Kingsea442/article/details/135341747

尽管 Spring Retry 工具能够优雅地实现重试,但它仍然存在两个不太友好的设计:

  1. 重试实体被限定为 Throwable 子类,这意味着重试针对的是可捕获的功能异常,但实际上我们可能希望依赖某个数据对象实体作为重试实体,但是 Spring Retry 框架必须强制将其转换为 Throwable 子类。
  2. 重试根源的断言对象使用的是 doWithRetry 的 Exception 异常实例,这不符合正常内部断言的返回设计。
    Spring Retry 建议使用注解来对方法进行重试,重试逻辑是同步执行的。重试的“失败”是指 Throwable 异常,如果你要通过返回值的某个状态来判断是否需要重试,则可能需要自己判断返回值并手动抛出异常。

Guava Retrying

开源地址:https://github.com/rholder/guava-retrying

Guava Retrying 是基于 Google 的核心类库 Guava 的重试机制实现的一个库,它提供了一种通用方法,可以使用 Guava 谓词匹配增强的特定停止、重试和异常处理功能来重试任意 Java 代码。这个库支持多种重试策略,比如指定重试次数、指定重试时间间隔等。此外,它还支持谓词匹配来确定是否应该重试,以及在重试时应该做些什么。Guava Retrying 的最大特点是它能够灵活地与其他 Guava 类库集成,这使得它非常易于使用。

pom依赖:

	// maven依赖<dependency><groupId>com.github.rholder</groupId><artifactId>guava-retrying</artifactId><version>2.0.0</version></dependency>// gradle依赖:compile "com.github.rholder:guava-retrying:2.0.0"

测试demo


public static void main(String[] args) {Callable<Boolean> callable = new Callable<Boolean>() {@Overridepublic Boolean call() throws Exception {// do something useful herelog.info("call...");throw new RuntimeException();}};Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()//retryIf 重试条件.retryIfException().retryIfRuntimeException().retryIfExceptionOfType(Exception.class).retryIfException(Predicates.equalTo(new Exception())).retryIfResult(Predicates.equalTo(false))//等待策略:每次请求间隔1s.withWaitStrategy(WaitStrategies.fixedWait(1, TimeUnit.SECONDS))//停止策略 : 尝试请求6次.withStopStrategy(StopStrategies.stopAfterAttempt(6))//时间限制 : 某次请求不得超过2s .withAttemptTimeLimiter(AttemptTimeLimiters.fixedTimeLimit(2, TimeUnit.SECONDS))//注册一个自定义监听器(可以实现失败后的兜底方法).withRetryListener(new MyRetryListener()).build();try {retryer.call(callable);} catch (Exception ee) {ee.printStackTrace();}
}

当发生重试之后,假如我们需要做一些额外的处理动作,比如发个告警邮件啥的,那么可以使用RetryListener。每次重试之后,guava-retrying会自动回调我们注册的监听。可以注册多个RetryListener,会按照注册顺序依次调用。

public class MyRetryListener implements RetryListener {@Overridepublic <V> void onRetry(Attempt<V> attempt) {// 第几次重试System.out.print("[retry]time=" + attempt.getAttemptNumber());// 距离第一次重试的延迟System.out.print(",delay=" + attempt.getDelaySinceFirstAttempt());// 重试结果: 是异常终止, 还是正常返回System.out.print(",hasException=" + attempt.hasException());System.out.print(",hasResult=" + attempt.hasResult());// 是什么原因导致异常if (attempt.hasException()) {System.out.print(",causeBy=" + attempt.getExceptionCause().toString());// do something useful here} else {// 正常返回时的结果System.out.print(",result=" + attempt.getResult());}System.out.println();}
}

RetryerBuilder是一个factory创建者,可以定制设置重试源且可以支持多个重试源,可以配置重试次数或重试超时时间,以及可以配置等待时间间隔,创建重试者Retryer实例。

RetryerBuilder的重试源支持Exception异常对象 和自定义断言对象,通过retryIfException 和retryIfResult设置,同时支持多个且能兼容。
retryIfException,抛出runtime异常、checked异常时都会重试,但是抛出error不会重试。

retryIfRuntimeException只会在抛runtime异常的时候才重试,checked异常和error都不重试。

retryIfExceptionOfType允许我们只在发生特定异常的时候才重试,比如NullPointerException和IllegalStateException都属于runtime异常,也包括自定义的error。

retryIfResult可以指定你的Callable方法在返回值的时候进行重试。

StopStrategy:停止重试策略,提供以下方式:

StopAfterDelayStrategy: 设定一个最长允许的执行时间;比如设定最长执行10s,无论任务执行次数,只要重试的时候超出了最长时间,则任务终止,并返回重试异常
NeverStopStrategy: 用于需要一直轮训知道返回期望结果的情况。
StopAfterAttemptStrategy: 设定最大重试次数,如果超出最大重试次数则停止重试,并返回重试异常。
WaitStrategy: 等待时长策略(控制时间间隔)
FixedWaitStrategy: 固定等待时长策略。
RandomWaitStrategy: 随机等待时长策略(可以提供一个最小和最大时长,等待时长为其区间随机值)
IncrementingWaitStrategy: 递增等待时长策略(提供一个初始值和步长,等待时间随重试次数增加而增加)。
ExponentialWaitStrategy: 指数等待时长策略
FibonacciWaitStrategy: 等待时长策略
ExceptionWaitStrategy: 异常时长等待策略
CompositeWaitStrategy: 复合时长等待策略

总结

Guava Retryer 工具与 Spring Retry 类似,都是通过定义重试者角色来包装正常逻辑重试。然而,Guava Retryer 在策略定义方面更优秀。它不仅支持设置重试次数和重试频度控制,还能够兼容多个异常或自定义实体对象的重试源定义,从而提供更多的灵活性。这使得 Guava Retryer 能够适用于更多的业务场景,比如网络请求、数据库访问等。此外,Guava Retryer 还具有很好的可扩展性,可以很方便地与其他 Guava 类库集成使用。

这篇关于使用Guava Retrying优雅的实现业务异常重试的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/593511

相关文章

Conda与Python venv虚拟环境的区别与使用方法详解

《Conda与Pythonvenv虚拟环境的区别与使用方法详解》随着Python社区的成长,虚拟环境的概念和技术也在不断发展,:本文主要介绍Conda与Pythonvenv虚拟环境的区别与使用... 目录前言一、Conda 与 python venv 的核心区别1. Conda 的特点2. Python v

Spring Boot中WebSocket常用使用方法详解

《SpringBoot中WebSocket常用使用方法详解》本文从WebSocket的基础概念出发,详细介绍了SpringBoot集成WebSocket的步骤,并重点讲解了常用的使用方法,包括简单消... 目录一、WebSocket基础概念1.1 什么是WebSocket1.2 WebSocket与HTTP

C#中Guid类使用小结

《C#中Guid类使用小结》本文主要介绍了C#中Guid类用于生成和操作128位的唯一标识符,用于数据库主键及分布式系统,支持通过NewGuid、Parse等方法生成,感兴趣的可以了解一下... 目录前言一、什么是 Guid二、生成 Guid1. 使用 Guid.NewGuid() 方法2. 从字符串创建

Python使用python-can实现合并BLF文件

《Python使用python-can实现合并BLF文件》python-can库是Python生态中专注于CAN总线通信与数据处理的强大工具,本文将使用python-can为BLF文件合并提供高效灵活... 目录一、python-can 库:CAN 数据处理的利器二、BLF 文件合并核心代码解析1. 基础合

Python使用OpenCV实现获取视频时长的小工具

《Python使用OpenCV实现获取视频时长的小工具》在处理视频数据时,获取视频的时长是一项常见且基础的需求,本文将详细介绍如何使用Python和OpenCV获取视频时长,并对每一行代码进行深入解析... 目录一、代码实现二、代码解析1. 导入 OpenCV 库2. 定义获取视频时长的函数3. 打开视频文

golang版本升级如何实现

《golang版本升级如何实现》:本文主要介绍golang版本升级如何实现问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录golanwww.chinasem.cng版本升级linux上golang版本升级删除golang旧版本安装golang最新版本总结gola

SpringBoot中SM2公钥加密、私钥解密的实现示例详解

《SpringBoot中SM2公钥加密、私钥解密的实现示例详解》本文介绍了如何在SpringBoot项目中实现SM2公钥加密和私钥解密的功能,通过使用Hutool库和BouncyCastle依赖,简化... 目录一、前言1、加密信息(示例)2、加密结果(示例)二、实现代码1、yml文件配置2、创建SM2工具

Mysql实现范围分区表(新增、删除、重组、查看)

《Mysql实现范围分区表(新增、删除、重组、查看)》MySQL分区表的四种类型(范围、哈希、列表、键值),主要介绍了范围分区的创建、查询、添加、删除及重组织操作,具有一定的参考价值,感兴趣的可以了解... 目录一、mysql分区表分类二、范围分区(Range Partitioning1、新建分区表:2、分

MySQL 定时新增分区的实现示例

《MySQL定时新增分区的实现示例》本文主要介绍了通过存储过程和定时任务实现MySQL分区的自动创建,解决大数据量下手动维护的繁琐问题,具有一定的参考价值,感兴趣的可以了解一下... mysql创建好分区之后,有时候会需要自动创建分区。比如,一些表数据量非常大,有些数据是热点数据,按照日期分区MululbU

Spring Boot @RestControllerAdvice全局异常处理最佳实践

《SpringBoot@RestControllerAdvice全局异常处理最佳实践》本文详解SpringBoot中通过@RestControllerAdvice实现全局异常处理,强调代码复用、统... 目录前言一、为什么要使用全局异常处理?二、核心注解解析1. @RestControllerAdvice2