首頁 > 軟體

Java利用設定重試策略解決超時問題

2022-10-16 14:04:08

在web應用中,由於網路原因或其他不可預測的原因,應用間會出現呼叫失敗的情形,通過設定重試策略可以有效解決外在原因導致的系統故障。

使用場景

  • 微服務間各個服務模組間的呼叫
  • 第三方模組遠端交易呼叫
  • 非業務異常導致可能失敗的情況

範例

構建Retryer

private Retryer retryer = RetryerBuilder.newBuilder()
        .retryIfException() // 異常時重試
        .retryIfResult(input -> input!=null && input instanceof Boolean && !Boolean.valueOf((Boolean) input)) // 返回值為false時重試
        // 對應Future獲取超時時間
        .withAttemptTimeLimiter(AttemptTimeLimiters.fixedTimeLimit(4, TimeUnit.SECONDS,Executors.newFixedThreadPool(2))) //重試次數限制
        .withRetryListener(new RetryListener() { // 重試執行邏輯
            @Override
            public <V> void onRetry(Attempt<V> attempt) {
                log.info("onRetry -> 重試次數:{},距第一次重試時長:{}", attempt.getAttemptNumber(),attempt.getDelaySinceFirstAttempt());
                if(attempt.hasException()){ // 是否異常導致重試
                    Throwable exception = attempt.getExceptionCause(); // 執行的異常
                    log.info("異常:{}", exception);
                }
                if(attempt.hasResult()){ // 是否有返回
                    V result = attempt.getResult();
                    log.info("返回:{}",result);
                }
            }
        })
        // 控制每次重試間隔時間,如果AttemptTimeLimiter設定多執行緒
        .withWaitStrategy(WaitStrategies.fixedWait(3,TimeUnit.SECONDS)) // 等待策略
        .withBlockStrategy(BlockStrategies.threadSleepStrategy()) // 阻塞策略
        //
        .withStopStrategy(StopStrategies.stopAfterAttempt(5)) // 停止策略
        .build();

使用Retryer讓業務程式碼擁有重試能力

前兩次執行時模擬返回false,則會執行重試;當第3次時,正常執行業務程式碼並返回true,結束重試

@Test
public void retryWhenResult() throws ExecutionException, RetryException {
   retryer.call(() -> {
       if(counter.incrementAndGet() == 3){// 模擬前2此返回false,觸發重試
           log.info(" 執行業務程式碼:{}次",counter.get());
           return true;
       }
       return false; 
   });
}

模擬前3次出現異常,則會執行重試;當第3次時,正常執行業務程式碼,結束重試

@Test
public void retryWhenException() throws ExecutionException, RetryException {
    retryer.call(() -> {
        if( counter.getAndIncrement() == 3 ){// 模擬前5此出現異常,觸發重試
            return counter;
        }
        log.info(" 執行業務程式碼: {}次", counter.get());
         throw new RuntimeException("ERROR"); 
    });
}

模擬前5此出現異常,由於Retryer設定重試次數為5,則最終業務程式碼不會執行

@Test
public void retryWhenResultOnFailure() throws ExecutionException, RetryException {
    retryer.call(() -> {
        if(counter.incrementAndGet() == 8){// 模擬前7此返回false,由於設定重試5次,因此最終失敗
            log.info(" 執行業務程式碼:{}次",counter.get());
            return true;
        }
        return false;
    });
}

執行流程

執行流程

通過RetryerBuilder構建Retryer,呼叫Retryer#call,封裝業務程式碼為其回撥函數

  • 開始迴圈執行
  • 由AttemptTimeLimiter#call執行回撥函數
  • 將結果封裝為Attempt,包括兩種型別ResultAttempt,ExceptionAttempt。如果成功,記錄執行結果、持續時長;如果失敗,記錄異常、持續時長
  • 執行監聽RetyrListener#onRetry,可以設定多個監聽
  • 執行拒絕斷言Predicate,根據返回值、執行異常、返回異常型別判斷是否終止重試
  • 如果滿足條件,則繼續重試;否則結束重試,並返回Attempt包含回撥結果
  • 根據終止策略StopStrategy判斷是否終止重試
  • 根據等待策略WaitStrategy獲取等待時長
  • 根據阻塞策略BlockStrategy與上一步等待時長阻塞重試,如果出現異常則丟擲RetryException
  • 重複執行以上邏輯

設定

構建Retryer主要通過RetryerBuilder.newBuilder()實現,其相關設定如下:

設定策略名稱描述
AttemptTimeLimiters 任務執行時長限制 
 NoAttemptTimeLimit無時長限制 
 FixedAttemptTimeLimit固定時長限制 
WaitStrategies 重試等待策略 
 ExponentialWaitStrategy指數等待策略按指數增加重試間隔時長,比如第一次2^1100、2^2100、2^3*100...最多300000
 FibonacciWaitStrategy斐波那契等待策略1100、1100、2100、3100、5*100...
 FixedWaitStrategy固定時長等待策略按設定的固定間隔時間
 RandomWaitStrategy隨機時長等待策略隨機間隔時間,可以設定隨機值範圍
 IncrementingWaitStrategy遞增等待策略根據設定的初始值與增量進行累加時間
 ExceptionWaitStrategy異常等待策略根據異常型別指定等待時間
 CompositeWaitStrategy複合等待策略可設定多個策略進行組合
BlockStrategies 阻塞策略根據WaitStrategies獲取阻塞時長
 ThreadSleepStrategy執行緒等等策略通過Thread.sleet()實現
StopStrategies 重試停止策略 
 NeverStopStrategy無限制策略 
 StopAfterAttemptStrategy限定次數策略 
 StopAfterDelayStrategy限定時長策略 
 NoAttemptTimeLimit限定次數 

注意

AttemptTimeLimiter中的FixedAttemptTimeLimit依賴於guava中的SimpleTimeLimiter,但是在guava高版本中該類已經成了私有類

總結

Guava Retrying模組能夠通過簡單的將程式碼實現業務邏輯重試的功能,並且其設定中包含了重試的次數、時長控制、重試阻塞、終止策略等等, 在專案中是非常常用的一項技術。

到此這篇關於Java利用設定重試策略解決超時問題的文章就介紹到這了,更多相關Java設定重試策略解決超時內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com