Java接口调用如何重试?GitHub Guava Retrying框架重试机制的使用

API远程接口在调用时会偶发网络超时、网络异常,导致调用失败,这时候某些特殊需求可能需要使用重试机制,当发生网络等异常时重新再发起调用请求。Github Retryer能完美的解决这一需求。

下面让我们看下如何使用Github Retryer。

1. 引入GitHub Retryer依赖

1
2
3
4
5
<dependency>
  <groupId>com.github.rholder</groupId>
  <artifactId>guava-retrying</artifactId>
  <version>2.0.0</version>
</dependency>

jar包下载地址:https://maven.ityuan.com/maven2/com/github/rholder/guava-retrying/2.0.0

2. 根据调用返回接口判断是否需要重试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
 
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;
/**
 * @description: GitHub Retryer框架重试机制的使用
 * @author ityuan.com
 * @date 2019年6月26日 上午11:07:38
 */
public class RetryTester {
 
    public static void main(String[] args) throws ExecutionException, RetryException {
         
        Retryer<Long> retryer = RetryerBuilder.<Long>newBuilder()
                // 返回false也需要重试
                .retryIfResult(Predicates.equalTo(1L))
                // 重调策略
                .withWaitStrategy(WaitStrategies.fixedWait(1, TimeUnit.SECONDS))
                // 尝试次数
                .withStopStrategy(StopStrategies.stopAfterAttempt(3))
                .build();
         
        retryer.call(new Callable<Long>() {
                @Override
                public Long call() throws Exception {
                    System.out.println("返回值是0L,看我能出现几次");
                    return 1L;
                }
            }
        );
         
    }
}

执行结果

1
2
3
4
5
6
返回值是0L,看我能出现几次
返回值是0L,看我能出现几次
返回值是0L,看我能出现几次
Exception in thread "main" com.github.rholder.retry.RetryException: Retrying failed to complete successfully after 3 attempts.
    at com.github.rholder.retry.Retryer.call(Retryer.java:120)
    at com.test.RetryTester.main(RetryTester.java:31)

3.根据调用发生异常判断是否需要重试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
 
import com.github.rholder.retry.RetryException;
import com.github.rholder.retry.Retryer;
import com.github.rholder.retry.RetryerBuilder;
import com.github.rholder.retry.StopStrategies;
/**
 * @description: GitHub Retryer框架重试机制的使用
 * @author ityuan.com
 * @date 2019年6月26日 上午11:07:38
 */
public class RetryTester2 {
 
    public static void main(String[] args) throws ExecutionException, RetryException {
         
        Retryer<Long> retryer = RetryerBuilder.<Long>newBuilder()
                .retryIfException()
                .withStopStrategy(StopStrategies.stopAfterAttempt(2)) // 重试2次后停止
                .build();
         
        retryer.call(new Callable<Long>() {
                @Override
                public Long call() throws Exception {
                    System.out.println("异常打印,看我能出现几次");
                    throw new RuntimeException();
                }
            }
        );
         
    }
}

执行结果

1
2
3
4
5
6
7
8
9
10
11
异常打印,看我能出现几次
异常打印,看我能出现几次
Exception in thread "main" com.github.rholder.retry.RetryException: Retrying failed to complete successfully after 2 attempts.
    at com.github.rholder.retry.Retryer.call(Retryer.java:120)
    at com.test.RetryTester2.main(RetryTester2.java:24)
Caused by: java.lang.RuntimeException
    at com.test.RetryTester2$1.call(RetryTester2.java:28)
    at com.test.RetryTester2$1.call(RetryTester2.java:1)
    at com.github.rholder.retry.AttemptTimeLimiters$NoAttemptTimeLimit.call(AttemptTimeLimiters.java:78)
    at com.github.rholder.retry.Retryer.call(Retryer.java:110)
    ... 1 more

4.添加异常监听

1
.withRetryListener(new MyRetryListener<>())

监听代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import com.github.rholder.retry.Attempt; 
import com.github.rholder.retry.RetryListener;
import java.util.concurrent.ExecutionException; 
   
@SuppressWarnings("hiding")
public class MyRetryListener<Long> implements RetryListener { 
   
    @Override 
    public <Long> void onRetry(Attempt<Long> 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
            Long 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(); 
    
}

总结

RetryerBuilder是一个factory创建者,可以定制设置重试源且可以支持多个重试源,可以配置重试次数或重试超时时间,以及可以配置等待时间间隔,创建重试者Retryer实例。

RetryerBuilder的重试源支持Exception异常对象 和自定义断言对象,通过retryIfException 和retryIfResult设置,同时支持多个且能兼容。

retryIfException,抛出runtime异常、checked异常时都会重试,但是抛出error不会重试。

retryIfRuntimeException只会在抛runtime异常的时候才重试,checked异常和error都不重试。

retryIfExceptionOfType允许我们只在发生特定异常的时候才重试,比如NullPointerException和IllegalStateException都属于runtime异常,也包括自定义的error


作者采用IT猿同步助手一键多平台发布,查看原文
posted @   立即行动  阅读(858)  评论(0编辑  收藏  举报
编辑推荐:
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
· DeepSeek 解答了困扰我五年的技术问题
阅读排行:
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
点击右上角即可分享
微信分享提示