Java接口調用如何重試?GitHub Guava Retrying框架重試機制的使用


API遠程接口在調用時會偶發網絡超時、網絡異常,導致調用失敗,這時候某些特殊需求可能需要使用重試機制,當發生網絡等異常時重新再發起調用請求。Github Retryer能完美的解決這一需求。

下面讓我們看下如何使用Github Retryer。

1. 引入GitHub Retryer依賴

<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. 根據調用返回接口判斷是否需要重試

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;
	            }
	        }
		);
		
	}
}

執行結果

返回值是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.根據調用發生異常判斷是否需要重試

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();
	            }
	        }
		);
		
	}
}

執行結果

異常打印,看我能出現幾次
異常打印,看我能出現幾次
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.添加異常監聽

.withRetryListener(new MyRetryListener<>()) 

監聽代碼

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猿同步助手一鍵多平台發布, 查看原文


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM