guava-retrying3 學(xué)習(xí)

使用場景

做自動化場景,對于一些數(shù)據(jù)統(tǒng)計,有時數(shù)據(jù)同步更新會遇到延遲的場景,延時的時間可能不確定,此時,如果用 sleep 一定時間的話,可能會造成時間的浪費。那么有什么方法了避免呢,比如使用重試機制,設(shè)置重試的時間和重試的次數(shù),當獲取不到數(shù)據(jù)時根據(jù)預(yù)定的時間來重新請求接口。

重試的實現(xiàn)的要素

  • 重試觸發(fā)時機
  • 什么條件去停止
  • 重試等待時間
  • 重試停止條件
  • 接口請求時間限制
  • 如果結(jié)束
  • 重試時的監(jiān)聽

guava-retrying 策略介紹

  • ** retryIfException() **: 當發(fā)生任何異常時觸發(fā)重試。
  • ** retryIfExceptionOfType(Class<? extends Throwable> exceptionType) ** : 當發(fā)生指定類型的異常時觸發(fā)重試。
  • ** retryIfRuntimeException() **:當發(fā)生 RuntimeException 或其子類異常時觸發(fā)重試。
  • ** retryIfResult(Predicate<R> resultPredicate) ** :根據(jù)返回結(jié)果的條件觸發(fā)重試。可以使用自定義的 Predicate 對返回結(jié)果進行判斷。
  • ** retryIfException(Predicate<Throwable> exceptionPredicate) **:根據(jù)異常的條件觸發(fā)重試??梢允褂米远x的 Predicate 對異常進行判斷。
  • ** withStopStrategy(StopStrategy stopStrategy) **:配置停止策略,指定在何時停止重試。常用的停止策略包括:
  • ** StopStrategies.stopAfterAttempt(int maxAttempts) **:在達到最大嘗試次數(shù)后停止重試。
  • ** StopStrategies.neverStop() **:永不停止重試,會一直進行重試
  • ** withWaitStrategy(WaitStrategy waitStrategy) **:配置等待策略,指定每次重試之間的等待時間。常用的等待策略包括:
    • ** WaitStrategies.fixedWait(long sleepTime, TimeUnit timeUnit) **:固定等待時間,每次重試之間等待指定的時間間隔。
    • ** WaitStrategies.randomWait(long minimumTime, long maximumTime, TimeUnit timeUnit) **:隨機等待時間,每次重試之間等待隨機的時間間隔。
  • ** withAttemptTimeLimiter(AttemptTimeLimiter<V> attemptTimeLimiter) **:配置重試時間限制器,用于限制每次重試的時間??梢允褂?FixedAttemptTimeLimit、ExponentialAttemptTimeLimit 或自定義的時間限制器。
  • ** withRetryListener(RetryListener retryListener) **:添加重試監(jiān)聽器,用于在重試過程中觸發(fā)相應(yīng)的事件。可以實現(xiàn) RetryListener 接口自定義監(jiān)聽器
  • ** withBlockStrategy() **:方法用于配置阻塞策略,指定在進行重試時的阻塞行為。阻塞策略定義了在重試之間是否需要進行阻塞等待,以及等待的方式和時長

構(gòu)造一個 Retryer

Retryer<T> retryer = RetryerBuilder.<T>newBuilder()
                .retryIfException()
                // 自定義重試條件
                .retryIfExceptionOfType(NeedRetryException.class)
                //停止策略,最大嘗試請求, attemptNumber次
                .withStopStrategy(StopStrategies.stopAfterAttempt(attemptNumber))
                //等待策略,每次請求間隔1s
                .withWaitStrategy(WaitStrategies.fixedWait(sleepTime, TimeUnit.SECONDS))
                //嘗試請求時間限制,不能超過 taskTime
                .withAttemptTimeLimiter(new FixedAttemptTimeLimit(taskTime, TimeUnit.SECONDS, Executors.newCachedThreadPool()))
                //方法用于配置阻塞策略,指定在進行重試時的阻塞行為
                .withBlockStrategy(spinBlockStrategy)
                //重試過程的監(jiān)聽策略,打印了嘗試的次數(shù)
                .withRetryListener(new RetryListener() {
                    @Override
                    public <V> void onRetry(Attempt<V> attempt) {
                        log.info("嘗試次數(shù) " + attempt.getAttemptNumber());
                    }
                })
                .build();

嘗試定義一個方法,使用 Callable 接口作為參數(shù)傳入一個執(zhí)行的任務(wù)

 public static <T> T retry(Callable<T> task, int attemptNumber, int sleepTime, int taskTime) throws Throwable {
        SpinBlockStrategy spinBlockStrategy = new SpinBlockStrategy();
        spinBlockStrategy.block(1);
        Retryer<T> retryer = RetryerBuilder.<T>newBuilder()
                .retryIfException()
                // 自定義重試條件
                .retryIfExceptionOfType(NeedRetryException.class)
                //停止策略,最大嘗試請求, attemptNumber次
                .withStopStrategy(StopStrategies.stopAfterAttempt(attemptNumber))
                //等待策略,每次請求間隔1s
                .withWaitStrategy(WaitStrategies.fixedWait(sleepTime, TimeUnit.SECONDS))
                //嘗試請求時間限制,不能超過 taskTime
                .withAttemptTimeLimiter(new FixedAttemptTimeLimit(taskTime, TimeUnit.SECONDS, Executors.newCachedThreadPool()))
                //方法用于配置阻塞策略,指定在進行重試時的阻塞行為
                .withBlockStrategy(spinBlockStrategy)
                //重試過程的監(jiān)聽策略,打印了嘗試的次數(shù)
                .withRetryListener(new RetryListener() {
                    @Override
                    public <V> void onRetry(Attempt<V> attempt) {
                        log.info("嘗試次數(shù) " + attempt.getAttemptNumber());
                    }
                })
                .build();
        try {
            return retryer.call(task);
        } catch (RetryException | ExecutionException e) {
            //throw inner exception
            String msg = "";
            log.error("retry internal error: {}", msg);
            throw new RuntimeException(msg);
        }
    }

guava-retrying3 結(jié)合testng使用,如果當我們Assert來作為判斷任務(wù)的嘗試條件時,有一個點需要注意,retry中的 call 方法最終拋出的對象為 throw new ExecutionError((Error)cause),這邊 new 出了一個 com.google.common.util.concurrent.ExecutionError 類的對象。而不是 java.util 類的。因此,我們需要重寫重試報錯類型


image.png

代碼中call的方法

retryer.call(task)

 private void wrapAndThrowRuntimeExecutionExceptionOrError(Throwable cause) {
        if (cause instanceof Error) {
            throw new ExecutionError((Error)cause);
        } else {
            throw new UncheckedExecutionException(cause);
        }
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容