使用guavaretryer优雅的实现接口重试机制

咸鱼 咸鱼     2022-10-11     795

关键词:

转载自:
使用Guava retrying优雅的实现接口重调机制
Guava retrying:基于 guava 的重试组件

实际项目中,为了考虑网络抖动,加锁并发冲突等场景,我们经常需要对异常操作进行重试。优雅的重试 其实就是将业务处理逻辑和重试逻辑分离。

下面是原文地址:


API 接口调用异常和网络异常在我们日常开发中经常会遇到,这种情况下我们需要先重试几次才能将其标识为错误并在确认错误之后发送异常提醒。

Guava retrying 可以灵活的实现这一功能。Guava retrying在支持重试次数和重试频度控制基础上,能够兼容支持多个异常或者自定义实体对象的重试源定义,让重试功能有更多的灵活性。Guava retrying也是线程安全的,入口调用逻辑采用的是Java.util.concurrent.Callable的call方法。

使用Guava retrying很简单,我们只要做以下几步:

pom文件

<guava-retry.version>2.0.0</guava-retry.version>
<dependency>
      <groupId>com.github.rholder</groupId>
      <artifactId>guava-retrying</artifactId>
      <version>${guava-retry.version}</version>
</dependency>

定义实现Callable接口的方法,以便Guava retrying能够调用

/**
    * @desc 更新可代理报销人接口
    * @author jianzhang11
    * @date 2017/3/31 15:17
    */
private static Callable<Boolean> updateReimAgentsCall = new Callable<Boolean>() {
   @Override
   public Boolean call() throws Exception {
       String url = ConfigureUtil.get(OaConstants.OA_REIM_AGENT);
       String result = HttpMethod.post(url, new ArrayList<BasicNameValuePair>());
       if(StringUtils.isEmpty(result)){
          throw new RemoteException("获取OA可报销代理人接口异常");
       }
       List<OAReimAgents> oaReimAgents = JSON.parseArray(result, OAReimAgents.class);
       if(CollectionUtils.isNotEmpty(oaReimAgents)){
           CacheUtil.put(Constants.REIM_AGENT_KEY,oaReimAgents);
           return true;
       }
       return false;
   }
};

定义Retry对象并设置相关策略

Retryer<Boolean> retryer = RetryerBuilder
                .<Boolean>newBuilder()
                // 抛出runtime异常、checked异常时都会重试,但是抛出error不会重试。
                .retryIfException()
                // 自定义 指定返回值 也需要重试:返回false也需要重试
                .retryIfResult(Predicates.equalTo(false))
                // 重试时间间隔
                .withWaitStrategy(WaitStrategies.fixedWait(10, TimeUnit.SECONDS))
                // 尝试次数
                .withStopStrategy(StopStrategies.stopAfterAttempt(3))
                .build();
 
    try {
        retryer.call(updateReimAgentsCall);
    } catch (ExecutionException e) {
        //e.printStackTrace();
    } catch (RetryException e) {
        logger.error("更新可代理报销人异常,需要发送提醒邮件");
    }

API说明

上面简单三步就能使用Guava retrying优雅的实现重调方法。接下来对其进行详细说明: 

  • RetryerBuilder是一个factory创建者,可以定制设置重试源且可以支持多个重试源,可以配置重试次数或重试超时时间,以及可以配置等待时间间隔,创建重试者Retryer实例。
  • RetryerBuilder的重试源支持Exception异常对象和自定义对象,通过retryIfException 和 retryIfResult设置,同时支持多个且能互相兼容。
  • retryIfException,抛出runtime异常、checked异常时都会重试,但是抛出error不会重试。
  • retryIfRuntimeException只会在抛runtime异常的时候才重试,checked异常和error都不重试。
  • retryIfExceptionOfType允许我们只在发生特定异常的时候才重试,比如 NullPointerException 和 IllegalStateException 都属于runtime异常,也包括自定义的error
    如:
.retryIfExceptionOfType(Error.class)// 只在抛出error重试

当然我们还可以在只有出现指定的异常的时候才重试,如:

.retryIfExceptionOfType(IllegalStateException.class)  
.retryIfExceptionOfType(NullPointerException.class)  

或者通过Predicate实现:

.retryIfException(Predicates.or(Predicates.instanceOf(NullPointerException.class),  
                Predicates.instanceOf(IllegalStateException.class))) 

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

// 返回false重试 
.retryIfResult(Predicates.equalTo(false))  
//以_error结尾才重试 
.retryIfResult(Predicates.containsPattern("_error$"))  
  • RetryListener:自定义重试监听器,可以用于异步记录错误日志,具体实例如下:

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

import com.github.rholder.retry.Attempt;  
import com.github.rholder.retry.RetryListener;  
import java.util.concurrent.ExecutionException;  
  
public class MyRetryListener<Boolean> implements RetryListener {  
  
    @Override  
    public <Boolean> void onRetry(Attempt<Boolean> 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());  
        } else {  
            // 正常返回时的结果  
            System.out.print(",result=" + attempt.getResult());  
        }  
  
        // bad practice: 增加了额外的异常处理代码  
        try {  
            Boolean result = attempt.get();  
            System.out.print(",rude get=" + result);  
        } catch (ExecutionException e) {  
            System.err.println("this attempt produce exception." + e.getCause().toString());  
        }  
  
        System.out.println();  
    }  
} 

接下来在Retry对象中指定监听:

.withRetryListener(new MyRetryListener<>())  

效果如下:

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

springboot一个注解实现重试机制,不能太优雅了。。。(代码片段)

来源:blog.csdn.net/h254931252/article/details/109257998前言在实际工作中,重处理是一个非常常见的场景,比如:发送消息失败。调用远程服务失败。争抢锁失败。这些错误可能是因为网络波动造成的,等待过后重处理就能... 查看详情

springboot一个注解搞定重试机制,不能太优雅了。。。

来源:blog.csdn.net/h254931252/article/details/109257998前言在实际工作中,重处理是一个非常常见的场景,比如:发送消息失败。调用远程服务失败。争抢锁失败。这些错误可能是因为网络波动造成的,等待过后重处理就能成功。通常来说... 查看详情

JSF 页面不使用过滤器接口重定向

】JSF页面不使用过滤器接口重定向【英文标题】:TheJSFpageins\'tredirectingusingbyFilterinterface【发布时间】:2012-05-1017:42:48【问题描述】:我正在开发jsf登录和注销较小的Web应用程序。我看到了一些问题。我的注销方法没有删除会话... 查看详情

如何在业务逻辑当中优雅引入重试机制(代码片段)

为什么要引入重试机制 我们首先看看正常的业务系统交互流程,就像下面图中所示一样,我们自己开发的系统通过HTTP接口或者通过RPC去访问其他业务系统,其他系统在没出现任何问题的情况下会返回给我们需要的数... 查看详情

如何优雅地实现c++编译期多态?

...的聚焦在运行期反射,本篇我们将聚焦在一个与反射使用的机制有所类同,但更依赖编译期特性的机制->编译期多态实现。引言前面的文章中我们更多的聚焦在运行期反射,本篇我们将聚焦在一个与反射使用的机制... 查看详情

rpc异常重试机制详解

...如何处理?catch一下,失败就再发起一次调用?这显然不优雅。考虑RPC框架的重试机制。2RPC框架的重试机制当调用端发起的请求失败时,RPC框架自身可进行重试,再重新发请求,用户可自行设置:是否开启重试重试次数RPC异常重... 查看详情

Azure 存储队列 - 重试机制实现

...tation【发布时间】:2021-01-1102:33:48【问题描述】:我正在使用nuget包"Microsoft.Azure.Storage.Queue"Version="11.1.7"创建Azure存储队列客户端,如下所示,AsyncLazy<CloudQueue>qClient=newAs 查看详情

华为od机试真题c++实现优雅子数组2022.11q4新题

...个数组中出现次数最多的元素出现大于等于K次,被称为K-优雅数组,k也可以被称为优雅阈值。例如,数组1,2,3,1、2,3,1,它是一个3-优雅数组,因为元素1出现次数大于等于3次,数组1,2,3,1,2就不是一个3-优雅数组,因为其中... 查看详情

华为od机试真题python实现优雅子数组2022.11q4新题

...个数组中出现次数最多的元素出现大于等于K次,被称为K-优雅数组,k也可以被称为优雅阈值。例如,数组1,2,3,1、2,3,1,它是一个3-优雅数组,因为元素1出现次数大于等于3次,数组1,2,3,1,2就不是一个3-优雅数组,因为其中... 查看详情

华为od机试真题java实现优雅子数组2022.11q4新题

...个数组中出现次数最多的元素出现大于等于K次,被称为K-优雅数组,k也可以被称为优雅阈值。例如,数组1,2,3,1、2,3,1,它是一个3-优雅数组,因为元素1出现次数大于等于3次,数组1,2,3,1,2就不是一个3-优雅数组,因为其中... 查看详情

40.少有人知的python“重试机制”

...家介绍的是一个第三方库-Tenacity,它实现了几乎我们可以使用到的所有重试场景,比如:在使用它之前,先要安装它无条件重试,重试之间无间隔无条件重试,但是在重试之前要等待2秒只重试7次重试10秒后不再重试或者上面两... 查看详情

零侵入性:一个注解,优雅的实现循环重试功能(代码片段)

前言在实际工作中,重处理是一个非常常见的场景,比如:发送消息失败。调用远程服务失败。争抢锁失败。这些错误可能是因为网络波动造成的,等待过后重处理就能成功。通常来说,会用try/catch,while循环... 查看详情

python实现华为od机试真题优雅子数组2023q1|200分(代码片段)

...个数组Q中出现次数最多的元素出现大于等于K次,被称为k-优雅数组,k也可以被称为优雅阈值只。例如:数组1,2,3,1、2,3,1,它是一个3-优雅数组,因为元素1出现次数大于等于3次,数组[1,2,3,1,2]就不是一一个3-优雅数组,因为其中出现... 查看详情

spring-retry(重试机制)(代码片段)

...在spring-retry中,所有配置都是基于简单注释的。二、使用步骤1.POM依赖基于AOP实现,因此还需引入aop相关的依赖<dependency><groupId>org.springframework.retry</groupId><artifactId>spring-retry</artifactId></dependency><de 查看详情

php实现curl重试机制(代码片段)

Failedconnecttowww.xxx.com:80;Connectiontimedout做了一下几点尝试:抓包分析,也没有分析出个所以然。以为是尝试连接的等待时间太小了,于是通过调整增大CURLOPT_CONNECTTIMEOUT参数,发现也无济于事。curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,10);//在... 查看详情

springcloudfeign重试机制-如何实现请求重试

参考技术Aapplication.yml中的HELLO-CLIENT.ribbon.....的配置是通过指定服务配置进行配置的ConnectTimeout:请求连接的超时时间ReadTimeout:请求处理的超时时间OkToRetryOnAllOperations:对所有操作请求都进行重试MaxAutoRetriesNextServer:切换实例的重试次... 查看详情

springcloud|feignclient和ribbon重试机制区别与联系

...重试。今天就来分别分析一下FeignClient和Ribbon重试机制的实现原理和区别,主要分为三点:1)FeignClient重试机制分析2)Ribbon重试机制分析3)FeignClient和Ribbon重试机制的区别于联系1)FeignClient重试机制分析:FeignCl 查看详情

tcp实现可靠传输的机制

实现可靠传输需要保证三个条件:(1)无比特差错传输(2)字节流不丢不重不乱序(3)接收方的处理能力大于发送速率****************************************************************TCP的首部检验和会检查首部和数据段,保证报文段无比特差错,满足条... 查看详情