重试利器之Guava-Retryer

写在前面

在日常开发中,我们经常会遇到需要调用外部服务和接口的场景。外部服务对于调用者来说一般都是不可靠的,尤其是在网络环境比较差的情况下,网络抖动很容易导致请求超时等异常情况,这时候就需要使用失败重试策略重新调用 API 接口来获取。重试策略在服务治理方面也有很广泛的使用,通过定时检测,来查看服务是否存活(Active)。

Guava Retrying是一个灵活方便的重试组件,包含了多种的重试策略,而且扩展起来非常容易。

用作者的话来说:

This is a small extension to Google’s Guava library to allow for the creation of configurable retrying strategies for an arbitrary function call, such as something that talks to a remote service with flaky uptime.

使用Guava-retrying你可以自定义来执行重试,同时也可以监控每次重试的结果和行为,最重要的基于 Guava 风格的重试方式真的很方便。

代码示例

  • 引入Guava-retry
<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 retryer能够调用
package org.java.base.retry;

import java.io.IOException;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.github.rholder.retry.RetryException;
import com.github.rholder.retry.Retryer;
import com.github.rholder.retry.RetryerBuilder;
import com.github.rholder.retry.StopStrategies;
import com.github.rholder.retry.WaitStrategies;
import com.google.common.base.Predicates;

public class RetryTest {
 private static final Logger logger = LoggerFactory.getLogger(RetryTest.class);
 public static void main(String[] args){ 
 Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
 .retryIfResult(Predicates.<Boolean>isNull())// 设置自定义段元重试源
 .retryIfExceptionOfType(Exception.class)// 设置异常重试源
 .retryIfRuntimeException()// 设置异常重试源
 .withStopStrategy(StopStrategies.stopAfterAttempt(5))// 设置重试5次,同样可以设置重试超时时间
 .withWaitStrategy(WaitStrategies.fixedWait(5L, TimeUnit.SECONDS))// 设置每次重试间隔,5秒
 .build();
 try {
 retryer.call(new Callable<Boolean>() {
 int i = 0;

 @Override
 public Boolean call() throws Exception {
 i++;
 logger.info("第{}次执行!", i);
 // do something
 if (i<6) {// 模拟错2次
 logger.info("模拟执行失败!");
 throw new IOException("异常");
 }
 logger.info("模拟执行成功!");
 return true; 
 }
 });
 } catch (RetryException e) {
 logger.info("超过重试次数", e);
 } catch (ExecutionException e) {
 logger.info("重试框架异常", e);
 }
 }


}

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

  • 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$"))  

运行结果如下:

1528257618(1)

主要接口及策略介绍:

Attempt:一次执行任务;

AttemptTimeLimiter:单次任务执行时间限制(如果单次任务执行超时,则终止执行当前任务);

BlockStrategies:任务阻塞策略(通俗的讲就是当前任务执行完,下次任务还没开始这段时间做什么……),默认策略为:BlockStrategies.THREAD_SLEEP_STRATEGY 也就是调用 Thread.sleep(sleepTime);

RetryException:重试异常;

RetryListener:自定义重试监听器,可以用于异步记录错误日志;

StopStrategy:停止重试策略,提供三种:

  • StopAfterDelayStrategy :设定一个最长允许的执行时间;比如设定最长执行10s,无论任务执行次数,只要重试的时候超出了最长时间,则任务终止,并返回重试异常RetryException
  • NeverStopStrategy :不停止,用于需要一直轮训知道返回期望结果的情况;
  • StopAfterAttemptStrategy :设定最大重试次数,如果超出最大重试次数则停止重试,并返回重试异常;

WaitStrategy:等待时长策略(控制时间间隔),返回结果为下次执行时长:

  • FixedWaitStrategy:固定等待时长策略;
  • RandomWaitStrategy:随机等待时长策略(可以提供一个最小和最大时长,等待时长为其区间随机值)
  • IncrementingWaitStrategy:递增等待时长策略(提供一个初始值和步长,等待时间随重试次数增加而增加)
  • ExponentialWaitStrategy:指数等待时长策略;
  • FibonacciWaitStrategy :Fibonacci 等待时长策略;
  • ExceptionWaitStrategy :异常时长等待策略;
  • CompositeWaitStrategy :复合时长等待策略;

参考资料:

http://blog.csdn.net/aitangyong/article/details/53894997

https://segmentfault.com/a/1190000006918410

http://blog.csdn.net/aitangyong/article/details/53886293

http://baijiahao.baidu.com/s?id=1575327487081031&wfr=spider&for=pc

http://www.cnblogs.com/jianzh5/p/6651799.html

 

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » 重试利器之Guava-Retryer

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址