guava-retrying基于guava的重试模块
简介
The guava-retrying module provides a general purpose method for retrying arbitrary Java code with specific stop, retry, and exception handling capabilities that are enhanced by Guava's predicate matching.
maven依赖
<dependency> <groupId>com.github.rholder</groupId> <artifactId>guava-retrying</artifactId> <version>2.0.0</version> </dependency>
使用说明
简单的demo
Callable<Boolean> callable = new Callable<Boolean>() { public Boolean call() throws Exception { return true; // do something useful here } }; Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder() .retryIfResult(Predicates.<Boolean>isNull()) .retryIfExceptionOfType(IOException.class) .retryIfRuntimeException() .withStopStrategy(StopStrategies.stopAfterAttempt(3)) .build(); try { retryer.call(callable); } catch (RetryException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); }
首先重试的内容主体必须是一个Callable
的实现,重试是根据其call
方法的执行状态(异常、返回值)定制的重试策略来进行重试的。
比如上面的列子。重试者retryer
由建造者RetryerBuilder
创建的,RetryerBuilder提供了各种方法来定制重试策略。
根据返回是否是null来决定是否重试
.retryIfResult(Predicates.<Boolean>isNull())
根据异常类型是否是IOException来决定是否重试
.retryIfExceptionOfType(IOException.class)
多个类型的时候还可以使用Predicate
Retryer<Void> retryer1 = RetryerBuilder.<Void>newBuilder() .retryIfException(Predicates.or(Predicates.instanceOf(NullPointerException.class), Predicates.instanceOf(IllegalStateException.class))) .withStopStrategy(StopStrategies.stopAfterAttempt(3)) // 重试3次后停止 .build();
根据异常是否是RuntimeException来决定是否重试
.retryIfRuntimeException()
设置重试的终止策略,尝试3次后终止
.withStopStrategy(StopStrategies.stopAfterAttempt(3))
除了上述重试判断外判断重试的方式与策略还有很多,比如
重试判断
返回值匹配
.retryIfResult(Predicates.containsPattern("_error$"))
.retryIfResult(Predicates.equalTo(2))
终止策略
常用的终止策略在com.github.rholder.retry.StopStrategies
中。
尝试3次后终止
.withStopStrategy(StopStrategies.stopAfterAttempt(3))
30s后终止
.withStopStrategy(StopStrategies.stopAfterDelay(30,TimeUnit.SECONDS))
不终止
.withStopStrategy(StopStrategies.neverStop())
等待策略
很多场景下并不是立即重试(环境影响,立即重试的失败率依旧很高),一般会等待一段时间后继续重试。
提供了等待策略,常用策略在com.github.rholder.retry.WaitStrategies
中。
比如
等待固定时间
.withWaitStrategy(WaitStrategies.fixedWait(5L, TimeUnit.SECONDS))
每次等待时间递增
.withWaitStrategy(WaitStrategies.incrementingWait(3, TimeUnit.SECONDS,1,TimeUnit.SECONDS))
斐波那契式等待
.withWaitStrategy(WaitStrategies.fibonacciWait())
重试监听
guava-retrying
提供每次重试的监听机制,每次重试后会回调注册的监听者,按顺序依次执行。
监听者必须实现RetryListener.onRetry
的方法。参数attempt
是每次尝试的记录。
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(); } }
增加监听者(可以增加多个,顺序执行)
.withRetryListener(new MyRetryListener<>()) .withRetryListener(new RetryListener() { @Override public <V> void onRetry(Attempt<V> attempt) { if (attempt.hasException()){ attempt.getExceptionCause().printStackTrace(); } } })
核心逻辑
long startTime = System.nanoTime(); for (int attemptNumber = 1; ; attemptNumber++) { Attempt<V> attempt; try { // 执行成功 V result = attemptTimeLimiter.call(callable); attempt = new ResultAttempt<V>(result, attemptNumber, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)); } catch (Throwable t) { // 执行失败 attempt = new ExceptionAttempt<V>(t, attemptNumber, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)); } // 监听器处理 for (RetryListener listener : listeners) { listener.onRetry(attempt); } // 是否符合终止策略 if (!rejectionPredicate.apply(attempt)) { return attempt.get(); } // 是否符合停止策略 if (stopStrategy.shouldStop(attempt)) { throw new RetryException(attemptNumber, attempt); } else { // 计算下次重试间隔时间 long sleepTime = waitStrategy.computeSleepTime(attempt); try { blockStrategy.block(sleepTime); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RetryException(attemptNumber, attempt); } } }
主要接口
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 :复合时长等待策略
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Mondrain支持kylin问题解决
Mondrain支持kylin问题解决 Mdx select {[MEASURES].[UNITPRICE],[MEASURES].[NUMBER]} on columns, {[CUSTOMER].[GENDER].members} on rows from saleinfo 问题 问题1: mondrian转换过来的sql kylin不支持:Cartesian Join is not supported. while executing SQL: "select "CUSTOMER"."GENDER" as "c0", sum("SALE"."UNITPRICE") as "m0", sum("SALE"."NUMBER") as "m1" from "SALE" as "SALE", "CUSTOMER" as "CUSTOMER" where "SALE"."CUSID" = "CUSTOMER"."CUSID" group by "CUSTOMER"."GENDER" 不支持笛卡儿积的写法=》对应源码修改1,2,3 问题2:No realization found for ...
- 下一篇
为什么使用TypeReference
在使用fastJson的时候对于泛型的反序列化很多场景下都会使用到TypeReference,例如: public static void main(String[] args) { List<String> list = new ArrayList<String>(); list.add("1"); list.add("2"); JSONObject o = new JSONObject(); o.put("k",list); List<String> types = o.getObject("k",List.class); System.out.println(JSON.toJSONString(types)); List<String> types2 = o.getObject("k",new TypeReference<List<String>>(){}); System.out.println(JSON.toJSONString(types2)); } 使用TypeReference可以明确的指定反序列化...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS7,CentOS8安装Elasticsearch6.8.6
- CentOS6,CentOS7官方镜像安装Oracle11G
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- CentOS8编译安装MySQL8.0.19
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- Windows10,CentOS7,CentOS8安装Nodejs环境
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7