【Guava】基于guava的重试组件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-retrying 的使用方式:
- 如果抛出 IOException 则重试,如果返回结果为 null 或者等于 2 则重试,固定等待时长为 300 ms,最多尝试 3 次;
Callable<Integer> task = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
return 2;
}
};
Retryer<Integer> retryer = RetryerBuilder.<Integer>newBuilder()
.retryIfResult(Predicates.<Integer>isNull())
.retryIfResult(Predicates.equalTo(2))
.retryIfExceptionOfType(IOException.class)
.withStopStrategy(StopStrategies.stopAfterAttempt(3))
.withWaitStrategy(WaitStrategies.fixedWait(300, TimeUnit.MILLISECONDS))
.build();
try {
retryer.call(task);
} catch (ExecutionException e) {
e.printStackTrace();
} catch (RetryException e) {
e.printStackTrace();
}
- 出现异常则执行重试,每次任务执行最长执行时间限定为 3 s,重试间隔时间初始为 3 s,最多重试 1 分钟,随着重试次数的增加每次递增 1 s,每次重试失败,打印日志;
@Override
public Integer call() throws Exception {
return 2;
}
};
Retryer<Integer> retryer = RetryerBuilder.<Integer>newBuilder()
.retryIfException()
.withStopStrategy(StopStrategies.stopAfterDelay(30,TimeUnit.SECONDS))
.withWaitStrategy(WaitStrategies.incrementingWait(3, TimeUnit.SECONDS,1,TimeUnit.SECONDS))
.withAttemptTimeLimiter(AttemptTimeLimiters.<Integer>fixedTimeLimit(3,TimeUnit.SECONDS))
.withRetryListener(new RetryListener() {
@Override
public <V> void onRetry(Attempt<V> attempt) {
if (attempt.hasException()){
attempt.getExceptionCause().printStackTrace();
}
}
})
.build();
try {
retryer.call(task);
} catch (ExecutionException e) {
e.printStackTrace();
} catch (RetryException e) {
e.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);
}
}
}
四、依赖引入
<dependency>
<groupId>com.github.rholder</groupId>
<artifactId>guava-retrying</artifactId>
<version>2.0.0</version>
</dependency>
默认的guava中也有包含。
五、主要接口介绍:
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 :复合时长等待策略;
【Guava】基于guava的重试组件Guava-Retryer的更多相关文章
- guava 学习笔记 使用瓜娃(guava)的选择和预判断使代码变得简洁
guava 学习笔记 使用瓜娃(guava)的选择和预判断使代码变得简洁 1,本文翻译自 http://eclipsesource.com/blogs/2012/06/06/cleaner-code- ...
- ☕【Java技术指南】「Guava Collections」实战使用相关Guava不一般的集合框架
Google Guava Collections 使用介绍 简介 Google Guava Collections 是一个对 Java Collections Framework 增强和扩展的一个开源 ...
- Guava-retry,java重试组件
使用场景 在日常开发中,我们经常会遇到需要调用外部服务和接口的场景.外部服务对于调用者来说一般都是不可靠的,尤其是在网络环境比较差的情况下,网络抖动很容易导致请求超时等异常情况,这时候就需要使用失败重 ...
- 基于vue项目的组件中导入mui框架初始化滑动等效果时需移除严格模式的问题
基于vue项目的组件中导入mui框架初始化滑动等效果时,控制台报错:Uncaught TypeError: 'caller', 'callee', and 'arguments' properties ...
- 基于log4net的日志组件扩展封装,实现自动记录交互日志 XYH.Log4Net.Extend(微服务监控)
背景: 随着公司的项目不断的完善,功能越来越复杂,服务也越来越多(微服务),公司迫切需要对整个系统的每一个程序的运行情况进行监控,并且能够实现对自动记录不同服务间的程序调用的交互日志,以及通一个服务或 ...
- 基于第三方vuejs库组件做适配性个性开发
相信大家在使用vuejs时候会用到很多的第三方库,能够找到适合自己的库并且加以使用可以大大加快进度,减少bug.但是很多时候会出现这样一个尴尬的境地: 基线的第三方组件并不能很好地满足我们自己地需求, ...
- 一个基于swoole的作业调度组件,已经实现了redis和rabitmq队列消息存储。
https://github.com/kcloze/swoole-jobs 一个基于swoole的作业调度组件,已经实现了redis和rabitmq队列消息存储.参考资料:swoole https:/ ...
- 如何基于 React 封装一个组件
如何基于 React 封装一个组件 前言 很多小伙伴在第一次尝试封装组件时会和我一样碰到许多问题,比如人家的组件会有 color 属性,我们在使用组件时传入组件文档中说明的属性值如 primary , ...
- Guava 教程2-深入探索 Google Guava 库
原文出处: oschina 在这个系列的第一部分里,我简单的介绍了非常优秀的Google collections和Guava类库,并简要的解释了作为Java程序员,如果使用Guava库来减少项目中大量 ...
随机推荐
- webapi Model Validation 模型验证
通常情况下,对于那些经常为别人提供数据接口的开发人员来说,对于调用方传递过来的参数都会有验证处理.例如: if (string.IsNullOrEmpty(entity.Name)) { //当姓名为 ...
- javascript 深度克隆
关键词 :递归 主要分为 数组 .对象.以及基本类型 function clone(Obj) { var buf; if (Obj instanceof Arr ...
- NideShop项目的安装部署教程
本文档为微信小程序商城NideShop项目的安装部署教程,欢迎star NideShop商城api服务:https://github.com/tumobi/nideshop NideShop微信小程序 ...
- javaWeb项目中到底什么是单例,多例
你用杯子喝可乐,喝完了不刷,继续去倒果汁喝,就是单例.你用杯子喝可乐,直接扔了杯子,换个杯子去倒果汁喝,就是多例. 数据库连接池就是单例模式,有且仅有一个连接池管理者,管理多个连接池对象. 1. 什么 ...
- [翻译] FastReport Class Hierarchy (FastReport 组件类层次结构)
"TfrxComponent" is the base class for all FastReport components. Objects of this type have ...
- Android实现表单提交,webapi接收
1.服务端采用的是.net的WEBAPI接口. 2.android多文件上传. 以下为核心代码: package com.example.my.androidupload; import androi ...
- h5页面宽度设置7.5rem
function ready() { var u = navigator.userAgent; var winW = document.documentElement.clientWidth; if ...
- leetcode 字符串转整数(atoi)
实现atoi,将字符串转为整数. 在找到第一个非空字符之前,需要移除掉字符串中的空格字符.如果第一个非空字符是正号或负号,选取该符号,并将其与后面尽可能多的连续的数字组合起来,这部分字符即为整数的值. ...
- Visual Studio 2017 如何 监控当前变量 占用内存空间大小
在进行VS调试时 大家是否想知道当前变量 占用了内存多少空间呢 这对系统调优还是很有帮助的吧
- c# 图片等比缩略
public Bitmap getnew(Image bit, int TargetWidth, int TargetHeight)//beishu参数为放大的倍数.放大缩小都可以,0.8即为缩小至原 ...