Java开发利器之重试器
代码中存在依赖不稳定的场景,需要使用重试获取预期结果或者尝试重新执行逻辑不立即结束,比如远程接口访问,数据加载访问,数据上传校验等 对于异常需要重试的场景,同时希望把正常逻辑和重试逻辑解耦 对方接口不支持异步回调
int time = 0;
do {
time++;
result = testRedo(); // 调用接口
} while (null == result && time < 5);
调用方需要不仅需要考虑多次调用的次数,还要考虑每次调用的间隔时间,尽量在最少调用情况下获取到最终结果(多一次请求意味着多一次网络开销,不方便实时调整) 多次调用过程中偶尔有一次调用出现异常(接口报错,网络异常),如果没有异常处理就会影响剩下次数的调用,无法保证高可用 多线程情况下上面的代码会出现并发问题,因为第一次调用的结果不一定是最早返回的,有可能后面调用的先返回,导致结果不是预期的 性能问题,如果使用多线程要考虑线程创建销毁和切换问题
支持设置重试次数和间隔时间,支持多种复杂场景的重试策略,延迟策略 而且支持多个异常或者自定义实体对象的重试源,让重试功能有更多的灵活性 线程安全,我们只需要关注我们的业务逻辑实现即可 内部使用线程池管理线程 基于命令模式使用链式调用,使用方便
pom依赖:
<dependency>
<groupId>com.github.rholdergroupId>
<artifactId>guava-retryingartifactId>
<version>2.0.0version>
dependency>
// 重试条件
Predicate<String> condition = response -> Objects.nonNull(response)
&& "处理中".equals(response.getReturnCode());
Optional<String> response = RetryUtil.retry(
condition, // 重试条件
() -> invoke(request), // 重试任务(比如调用接口)
500, // 500ms重试一次, 可以做成配置化
3); // 一共重试3次, 可以做成配置化
return response.orElse(null);
/**
* 根据输入的condition重复做task,在规定的次数内达到condition则返回,
* 如果超过retryTimes则返回null, 重试次数,整个重试时间以及retry exception都会记录log
*
* @param condition 重试条件,比如接口返回errorCode为处理中,或不是最终需要的结果
* @param task 重试做的任务
* @param sleepTime 重试间隔时间,单位毫秒
* @param retryTimes 重试次数
* @return targetBean
*/
public static
Optional retry(Predicate {condition, Callable task, int sleepTime, int retryTimes) Optional
result = Optional.empty(); StopWatch stopWatch = new StopWatch();
try {
stopWatch.start();
Retryer
retry = RetryerBuilder. newBuilder() // 默认任务执行过程中发生异常自动重试
.retryIfException()
// 重试条件(按照业务场景)
.retryIfResult(condition)
// 等待策略
.withWaitStrategy(WaitStrategies.fixedWait(sleepTime, TimeUnit.MILLISECONDS))
// 重试策略
.withStopStrategy(StopStrategies.stopAfterAttempt(retryTimes))
// 重试监听器
.withRetryListener(new RetryListener() {
public
void onRetry(Attempt attempt) {// 记录重试次数和异常信息
log.info(MessageFormat.format("{0}th retry", attempt.getAttemptNumber()));
if (attempt.hasException()) {
log.error(MessageFormat.format("retry exception:{0}", attempt.getExceptionCause()));
}
}
}).build();
// 开始执行重试任务
result = Optional.ofNullable(retry.call(task));
} catch (Exception e) {
log.error("retry fail:", e.getMessage());
} finally {
stopWatch.stop();
log.info("retry execute time", stopWatch.getTime());
}
return result;
}
AttemptTimeLimiter:单次任务执行时间限制(如果单次任务执行超时,则终止执行当前任务) BlockStrategies:任务阻塞策略,默认策略为:BlockStrategies.THREAD_SLEEP_STRATEGY,也就是调用Thread.sleep () StopStrategy:停止重试策略,提供三种: StopAfterDelayStrategy:设定一个最长允许的执行时间,比如设定最长执行10s,无论任务执行次数,只要重试的时候超出了最长时间,则任务终止,并返回重试异常RetryException NeverStopStrategy:不停止,用于需要一直轮询直到返回期望结果的情况
WaitStrategy:等待时长策略(控制时间间隔),返回结果为下次执行时长:
评论