一般在各种业务场景中,为了保持系统稳定,我们都会有相应的重试机制,因为比如说,某个接口某个数据库链接由于网络抖动或者其他因素导致响应失败,这时候直接判定失败或者Mock数据未必是一种优雅的方式,因为这种情况下未必是接口挂掉了或者数据库连不上了,有可能是网络一时的抖动导致的,所以这时候一个优雅的重试机制或许能帮上我们。
Guava Retry模块提供了一种通用方法, 可以使用Guava谓词匹配增强的特定停止、重试和异常处理功能来重试任意Java代码。
https://github.com/rholder/guava-retrying
Guava retryer工具与spring-retry类似,都是通过定义重试者角色来包装正常逻辑重试,但是Guava retryer有更优的策略定义,在支持重试次数和重试频度控制基础上,能够兼容支持多个异常或者自定义实体对象的重试源定义,让重试功能有更多的灵活性。
Guava Retryer也是线程安全的,入口调用逻辑采用的是 java.util.concurrent.Callable 的 call() 方法
<dependency>
<groupId>com.github.rholder</groupId>
<artifactId>guava-retrying</artifactId>
<version>2.0.0</version>
</dependency>
创建一个可以永远重试的 Retryer,在每次失败的重试之后,以递增指数的间隔等待直到最多5分钟。5分钟后,每隔5分钟重试一次。
Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
.retryIfExceptionOfType(IOException.class)
.retryIfRuntimeException()
.withWaitStrategy(WaitStrategies.exponentialWait(100, 5, TimeUnit.MINUTES))
.withStopStrategy(StopStrategies.neverStop())
.build();
创建一个可以永远重试的 Retryer,在每次失败的重试之后,增加斐波那契回退间隔,直到最多2分钟。2分钟后,每隔2分钟重试一次。
Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
.retryIfExceptionOfType(IOException.class)
.retryIfRuntimeException()
.withWaitStrategy(WaitStrategies.fibonacciWait(100, 2, TimeUnit.MINUTES))
.withStopStrategy(StopStrategies.neverStop())
.build();
//定义重试机制
Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
//retryIf 重试条件
.retryIfException()
.retryIfRuntimeException()
.retryIfExceptionOfType(Exception.class)
.retryIfException(Predicates.equalTo(new Exception()))
.retryIfResult(Predicates.equalTo(false))
//等待策略:每次请求间隔1s
.withWaitStrategy(WaitStrategies.fixedWait(1, TimeUnit.SECONDS))
//停止策略 : 尝试请求6次
.withStopStrategy(StopStrategies.stopAfterAttempt(6))
//时间限制 : 某次请求不得超过2s , 类似: TimeLimiter timeLimiter = new SimpleTimeLimiter();
.withAttemptTimeLimiter(AttemptTimeLimiters.fixedTimeLimit(2, TimeUnit.SECONDS))
.build();
import com.github.rholder.retry.*;
import com.google.common.base.Predicates;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
@Slf4j
public class RetryerDemo {
public static void main(String[] args) {
//定义请求实现
Callable<Boolean> callable = new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
// do something useful here
log.info("call...");
throw new RuntimeException();
}
};
//定义重试机制
Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
// retryIf 重试条件
.retryIfResult(Predicates.isNull())
.retryIfExceptionOfType(IOException.class)
.retryIfRuntimeException()
.withStopStrategy(StopStrategies.stopAfterAttempt(3))
.build();
try {
retryer.call(callable);
} catch (RetryException | ExecutionException e) {
e.printStackTrace();
}
}
}
输出:
com.github.rholder.retry.RetryException: Retrying failed to complete successfully after 3 attempts.
at com.github.rholder.retry.Retryer.call(Retryer.java:174)
at com.spring.master.spring.guava.retryer.RetryerDemo.main(RetryerDemo.java:39)
Caused by: java.lang.RuntimeException
at com.spring.master.spring.guava.retryer.RetryerDemo$1.call(RetryerDemo.java:27)
at com.spring.master.spring.guava.retryer.RetryerDemo$1.call(RetryerDemo.java:22)
at com.github.rholder.retry.AttemptTimeLimiters$NoAttemptTimeLimit.call(AttemptTimeLimiters.java:78)
at com.github.rholder.retry.Retryer.call(Retryer.java:160)
... 1 more
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有