使用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

相关文章

SpringBoot集成XXL-JOB实现任务管理全流程

《SpringBoot集成XXL-JOB实现任务管理全流程》XXL-JOB是一款轻量级分布式任务调度平台,功能丰富、界面简洁、易于扩展,本文介绍如何通过SpringBoot项目,使用RestTempl... 目录一、前言二、项目结构简述三、Maven 依赖四、Controller 代码详解五、Service

Python 基于http.server模块实现简单http服务的代码举例

《Python基于http.server模块实现简单http服务的代码举例》Pythonhttp.server模块通过继承BaseHTTPRequestHandler处理HTTP请求,使用Threa... 目录测试环境代码实现相关介绍模块简介类及相关函数简介参考链接测试环境win11专业版python

GO语言短变量声明的实现示例

《GO语言短变量声明的实现示例》在Go语言中,短变量声明是一种简洁的变量声明方式,使用:=运算符,可以自动推断变量类型,下面就来具体介绍一下如何使用,感兴趣的可以了解一下... 目录基本语法功能特点与var的区别适用场景注意事项基本语法variableName := value功能特点1、自动类型推

GO语言中函数命名返回值的使用

《GO语言中函数命名返回值的使用》在Go语言中,函数可以为其返回值指定名称,这被称为命名返回值或命名返回参数,这种特性可以使代码更清晰,特别是在返回多个值时,感兴趣的可以了解一下... 目录基本语法函数命名返回特点代码示例命名特点基本语法func functionName(parameters) (nam

基于Python实现自动化邮件发送系统的完整指南

《基于Python实现自动化邮件发送系统的完整指南》在现代软件开发和自动化流程中,邮件通知是一个常见且实用的功能,无论是用于发送报告、告警信息还是用户提醒,通过Python实现自动化的邮件发送功能都能... 目录一、前言:二、项目概述三、配置文件 `.env` 解析四、代码结构解析1. 导入模块2. 加载环

使用shardingsphere实现mysql数据库分片方式

《使用shardingsphere实现mysql数据库分片方式》本文介绍如何使用ShardingSphere-JDBC在SpringBoot中实现MySQL水平分库,涵盖分片策略、路由算法及零侵入配置... 目录一、ShardingSphere 简介1.1 对比1.2 核心概念1.3 Sharding-Sp

Java 正则表达式的使用实战案例

《Java正则表达式的使用实战案例》本文详细介绍了Java正则表达式的使用方法,涵盖语法细节、核心类方法、高级特性及实战案例,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要... 目录一、正则表达式语法详解1. 基础字符匹配2. 字符类([]定义)3. 量词(控制匹配次数)4. 边

Python Counter 函数使用案例

《PythonCounter函数使用案例》Counter是collections模块中的一个类,专门用于对可迭代对象中的元素进行计数,接下来通过本文给大家介绍PythonCounter函数使用案例... 目录一、Counter函数概述二、基本使用案例(一)列表元素计数(二)字符串字符计数(三)元组计数三、C

Java+AI驱动实现PDF文件数据提取与解析

《Java+AI驱动实现PDF文件数据提取与解析》本文将和大家分享一套基于AI的体检报告智能评估方案,详细介绍从PDF上传、内容提取到AI分析、数据存储的全流程自动化实现方法,感兴趣的可以了解下... 目录一、核心流程:从上传到评估的完整链路二、第一步:解析 PDF,提取体检报告内容1. 引入依赖2. 封装

使用Spring Cache本地缓存示例代码

《使用SpringCache本地缓存示例代码》缓存是提高应用程序性能的重要手段,通过将频繁访问的数据存储在内存中,可以减少数据库访问次数,从而加速数据读取,:本文主要介绍使用SpringCac... 目录一、Spring Cache简介核心特点:二、基础配置1. 添加依赖2. 启用缓存3. 缓存配置方案方案