【Guava】基於guava的重試組件Guava-Retryer

1、使用場景

在平常開發中,咱們常常會遇到須要調用外部服務和接口的場景。外部服務對於調用者來講通常都是不可靠的,尤爲是在網絡環境比較差的狀況下,網絡抖動很容易致使請求超時等異常狀況,這時候就須要使用失敗重試策略從新調用 API 接口來獲取。重試策略在服務治理方面也有很普遍的使用,經過定時檢測,來查看服務是否存活(
Active)。java

Guava Retrying 是一個靈活方便的重試組件,包含了多種的重試策略,並且擴展起來很是容易。git

用做者的話來講:github

This is a small extension to Google’s Guava library to allow for the creation of configurable retrying strategies for an arbitrary function call, such as something that talks to a remote service with flaky uptime.網絡

使用 Guava-retrying 你能夠自定義來執行重試,同時也能夠監控每次重試的結果和行爲,最重要的基於 Guava 風格的重試方式真的很方便。app

2、代碼示例

如下會簡單列出 guava-retrying 的使用方式:dom

  • 若是拋出 IOException 則重試,若是返回結果爲 null 或者等於 2 則重試,固定等待時長爲 300 ms,最多嘗試 3 次;
Callable<Integer> task = new Callable<Integer>() {
    @Override
    public Integer call() throws Exception {
        return 2;
    }
};

Retryer<Integer> retryer = RetryerBuilder.<Integer>newBuilder()
        .retryIfResult(Predicates.<Integer>isNull())
        .retryIfResult(Predicates.equalTo(2))
        .retryIfExceptionOfType(IOException.class)
        .withStopStrategy(StopStrategies.stopAfterAttempt(3))
        .withWaitStrategy(WaitStrategies.fixedWait(300, TimeUnit.MILLISECONDS))
        .build();
try {
    retryer.call(task);
} catch (ExecutionException e) {
    e.printStackTrace();
} catch (RetryException e) {
    e.printStackTrace();
}
  • 出現異常則執行重試,每次任務執行最長執行時間限定爲 3 s,重試間隔時間初始爲 3 s,最多重試 1 分鐘,隨着重試次數的增長每次遞增 1 s,每次重試失敗,打印日誌;
@Override
    public Integer call() throws Exception {
        return 2;
    }
};

Retryer<Integer> retryer = RetryerBuilder.<Integer>newBuilder()
        .retryIfException()
        .withStopStrategy(StopStrategies.stopAfterDelay(30,TimeUnit.SECONDS))
        .withWaitStrategy(WaitStrategies.incrementingWait(3, TimeUnit.SECONDS,1,TimeUnit.SECONDS))
        .withAttemptTimeLimiter(AttemptTimeLimiters.<Integer>fixedTimeLimit(3,TimeUnit.SECONDS))
        .withRetryListener(new RetryListener() {
            @Override
            public <V> void onRetry(Attempt<V> attempt) {
                if (attempt.hasException()){
                    attempt.getExceptionCause().printStackTrace();
                }
            }
        })
        .build();
try {
    retryer.call(task);
} catch (ExecutionException e) {
    e.printStackTrace();
} catch (RetryException e) {
    e.printStackTrace();
}

3、核心執行邏輯

long startTime = System.nanoTime();
for (int attemptNumber = 1; ; attemptNumber++) {
    Attempt<V> attempt;
    try {
        // 執行成功
        V result = attemptTimeLimiter.call(callable);
        attempt = new ResultAttempt<V>(result, attemptNumber, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime));
    } catch (Throwable t) {
        // 執行失敗
        attempt = new ExceptionAttempt<V>(t, attemptNumber, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime));
    }
    // 監聽器處理
    for (RetryListener listener : listeners) {
        listener.onRetry(attempt);
    }
    // 是否符合終止策略
    if (!rejectionPredicate.apply(attempt)) {
        return attempt.get();
    }
    // 是否符合中止策略
    if (stopStrategy.shouldStop(attempt)) {
        throw new RetryException(attemptNumber, attempt);
    } else {
        // 計算下次重試間隔時間
        long sleepTime = waitStrategy.computeSleepTime(attempt);
        try {
            blockStrategy.block(sleepTime);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RetryException(attemptNumber, attempt);
        }
    }
}

4、依賴引入

<dependency>
      <groupId>com.github.rholder</groupId>
      <artifactId>guava-retrying</artifactId>
      <version>2.0.0</version>
</dependency>

默認的guava中也有包含。異步

5、主要接口介紹:

  • Attempt:一次執行任務;ide

  • AttemptTimeLimiter:單次任務執行時間限制(若是單次任務執行超時,則終止執行當前任務);ui

  • BlockStrategies:任務阻塞策略(通俗的講就是當前任務執行完,下次任務還沒開始這段時間作什麼……),默認策略爲:BlockStrategies.THREAD_SLEEP_STRATEGY 也就是調用 Thread.sleep(sleepTime);日誌

  • RetryException:重試異常;

  • RetryListener:自定義重試監聽器,能夠用於異步記錄錯誤日誌;

  • StopStrategy:中止重試策略,提供三種:

    • StopAfterDelayStrategy :設定一個最長容許的執行時間;好比設定最長執行10s,不管任務執行次數,只要重試的時候超出了最長時間,則任務終止,並返回重試異常RetryException;
    • NeverStopStrategy :不中止,用於須要一直輪訓知道返回指望結果的狀況;
    • StopAfterAttemptStrategy :設定最大重試次數,若是超出最大重試次數則中止重試,並返回重試異常;
  • WaitStrategy:等待時長策略(控制時間間隔),返回結果爲下次執行時長:

    • FixedWaitStrategy:固定等待時長策略;
    • RandomWaitStrategy:隨機等待時長策略(能夠提供一個最小和最大時長,等待時長爲其區間隨機值)
    • IncrementingWaitStrategy:遞增等待時長策略(提供一個初始值和步長,等待時間隨重試次數增長而增長)
    • ExponentialWaitStrategy:指數等待時長策略;
    • FibonacciWaitStrategy :Fibonacci 等待時長策略;
    • ExceptionWaitStrategy :異常時長等待策略;
    • CompositeWaitStrategy :複合時長等待策略;
相關文章
相關標籤/搜索