<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      重試機制的實現(Guava Retry)

      重試機制的實現

      重試作用:

      對于重試是有場景限制的,參數校驗不合法、寫操作等(要考慮寫是否冪等)都不適合重試。

      遠程調用超時、網絡突然中斷可以重試。外部 RPC 調用,或者數據入庫等操作,如果一次操作失敗,可以進行多次重試,提高調用成功的可能性

      優雅的重試機制要具備幾點:

      • 無侵入:這個好理解,不改動當前的業務邏輯,對于需要重試的地方,可以很簡單的實現
      • 可配置:包括重試次數,重試的間隔時間,是否使用異步方式等
      • 通用性:最好是無改動(或者很小改動)的支持絕大部分的場景,拿過來直接可用

      重試實現方式

      1 切面方式

      在需要添加重試的方法上添加一個用于重試的自定義注解,然后在切面中實現重試的邏輯,主要的配置參數則根據注解中的選項來初始化

      優點:

      • 真正的無侵入

      缺點:

      • 某些方法無法被切面攔截的場景無法覆蓋(如spring-aop無法切私有方法,final方法)

        直接使用aspecj則有些小復雜;如果用spring-aop,則只能切被spring容器管理的bean

      2 消息總線方式

      這個也比較容易理解,在需要重試的方法中,發送一個消息,并將業務邏輯作為回調方法傳入;由一個訂閱了重試消息的consumer來執行重試的業務邏輯

      優點:

      • 重試機制不受任何限制,即在任何地方你都可以使用

        利用EventBus框架,可以非常容易把框架搭起來

      缺點:

      • 業務侵入,需要在重試的業務處,主動發起一條重試消息

        調試理解復雜(消息總線方式的最大優點和缺點,就是過于靈活了,你可能都不知道什么地方處理這個消息,特別是新的童鞋來維護這段代碼時)

        如果要獲取返回結果,不太好處理, 上下文參數不好處理

      3 模板方式(定義一個抽象類,業務邏輯進行繼承) 類似與代理模式

      4 spring-retry框架(注解)

      Guava Retry實現以及使用

      1. 使用Guava Retry

      1.1 引入依賴

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

      1.2 構建retryer

      private static Retryer<Integer> retryer = RetryerBuilder.newBuilder()
          //異常重試
          .retryIfException()
          //運行時異常
          .retryIfRuntimeException()
          //某種類型的異常
          .retryIfExceptionOfType(ServiceRuntimeException.class)
          //符合異常條件
          .retryIfException(Predicates.equalTo(new Exception()))
          //結果符合某種條件
          .retryIfResult(Predicates.equalTo(false))
          //重試等待時間
          .withWaitStrategy(WaitStrategies.fixedWait(3, TimeUnit.SECONDS))
          //停止條件
          .withStopStrategy(StopStrategies.stopAfterAttempt(3))
          //監聽器
          .withRetryListener(new MyRetryListener())
          
          //重試限制器(每一次執行的時間)
          .withAttemptTimeLimiter(AttemptTimeLimiters.fixedTimeLimit(1, TimeUnit.SECONDS))
          .build();
      
          //監聽器
          .withRetryListener(new RetryListener() {
              @Override
              public <V> void onRetry(Attempt<V> attempt) {
                  log.info("listener receive attempt={}",attempt);
              }
          })
          
      

      1.3 主邏輯放在callable里,傳給retryer進行調用

      public int mockQueryDB() {
          Callable<Integer> callable = new Callable<Integer>() {
              @Override
              public Integer call() throws Exception {
                  return doQuery();
              }
          };
      }
      
      //源碼
      public V call(Callable<V> callable) throws ExecutionException, RetryException{
          
      }
      
      @FunctionalInterface
      public interface Callable<V> {
          /**
           * Computes a result, or throws an exception if unable to do so.
           *
           * @return computed result
           * @throws Exception if unable to compute a result
           */
          V call() throws Exception;
      }
      

      1.4 執行

      根據配置,當發生異常時,會重試,最多執行3次。每次嘗試中間會等待3秒。
      如果執行3次,仍然報錯,那么retryer.call會報RetryException:

      int result;
      try {
          result = retryer.call(callable);
          //或者  返回值為泛型 最終為object 需要強制轉化
          result = (int) requestRetryer.call(() -> doQuery());
      } catch (Exception e) {
          result = -1;
      }
      return result;
      
      com.github.rholder.retry.RetryException: Retrying failed to complete successfully after 3 attempts.
      

      2. retryIfException

      guava retry支持多種條件下重試

      2.1 retryIfException()

      這個就是在任何異常發生時,都會進行重試。

      .retryIfException()
      

      2.2 retryIfRuntimeException()

      這個是指,只有runtime exception發生時,才會進行重試。

      .retryIfRuntimeException()
      

      2.3 retryIfExceptionOfType

      發生某種指定異常時,才重試。例如

      .retryIfExceptionOfType(DBException.class)
      

      2.4 retryIfException(@Nonnull Predicate exceptionPredicate)

      傳入一個條件,滿足條件,就會觸發重試。

      .retryIfException(e -> e.getMessage().contains("NullPointerException"))
      

      2.5 多個retryIfException串起來時,滿足其中之一,就會觸發重試。

      .retryIfExceptionOfType(DBException.class)
      .retryIfException(e -> e.getMessage().contains("NullPointerException"))
      

      3. retryIfResult

      當執行沒有發生異常,但是當返回某些結果時,依然想進行重試,那么就可以使用retryIfResult。

      .retryIfResult(e -> e.intValue() == 0) //當返回值為0時,會觸發重試。
      

      4. StopStrategies

      重試器的終止策略配置,默認不終止

      4.1 StopStrategies.stopAfterAttempt

      重試超過最大次數后終止

      .withStopStrategy(StopStrategies.stopAfterAttempt(3))
      

      4.2 StopStrategies.stopAfterDelay

      指定時間,多次嘗試直到指定時間。

      .withStopStrategy(StopStrategies.stopAfterDelay(10, TimeUnit.SECONDS))
      

      4.3 StopStrategies.neverStop

      一直重試,不會停止。如果不指定StopStrategies,似乎也是一樣的效果。

      .withStopStrategy(StopStrategies.neverStop())
      

      4.4 同時設置多個StopStrategies?

      不能設置多個,會報錯:

      java.lang.IllegalStateException: a stop strategy has already been set 
      com.github.rholder.retry.StopStrategies$StopAfterAttemptStrategy@21c7208d
      

      5. WaitStrategies

      重試器到的等待策略配,配置每次重試失敗后的休眠時間

      5.1 WaitStrategies.fixedWait

      重試前休眠固定時間

      .withWaitStrategy(WaitStrategies.fixedWait(1, TimeUnit.SECONDS))
      

      5.2 WaitStrategies.exponentialWait

      指數增長休眠時間,2的attempTime次冪

      // 第一二次之間等待 2 ms,接下來等 2*2 ms, 2*2*2 ms, ...
      .withWaitStrategy(WaitStrategies.exponentialWait())
      
      //指數等待時間,最多10s。超過10s,也只等待10s。
      .withWaitStrategy(WaitStrategies.exponentialWait(10, TimeUnit.SECONDS))
      
      // 等待時間乘以 5的系數。指數級增長,最多不超過10s.
      .withWaitStrategy(WaitStrategies.exponentialWait(5, 10, TimeUnit.SECONDS))
      

      5.3 WaitStrategies.fibonacciWait

      以斐波那契數列的方式增長。參數含義與exponentialWait類似。

      .withWaitStrategy(WaitStrategies.fibonacciWait())
      .withWaitStrategy(WaitStrategies.fibonacciWait(10, TimeUnit.SECONDS))
      .withWaitStrategy(WaitStrategies.fibonacciWait(5, 10, TimeUnit.SECONDS))
      

      5.4 WaitStrategies.exceptionWait

      對于不同的異常類型,定義不同的等待時間策略。

      .withWaitStrategy(WaitStrategies.exceptionWait(DBException.class, x -> 50l))
      

      5.5 WaitStrategies.randomWait

      重試前休眠minimumTime~maximumTime之間隨機時間

      //等待時間為 0 到3秒 之間的隨機時間
      .withWaitStrategy(WaitStrategies.randomWait(3, TimeUnit.SECONDS))
      
      //等待時間為 1秒到3秒之間的隨機時間
      .withWaitStrategy(WaitStrategies.randomWait(1, TimeUnit.SECONDS, 3, TimeUnit.SECONDS))
      

      5.6 WaitStrategies.incrementingWait

      第一次重試休眠initialSleepTime,后續每次重試前休眠時間線性遞增increment。例如,第一二次之間等待1秒,接下來每次增加3秒。

      .withWaitStrategy(WaitStrategies.incrementingWait(1, TimeUnit.SECONDS, 3, TimeUnit.SECONDS))
      

      5.7 WaitStrategies.noWait

      不等待,直接重試。

      .withWaitStrategy(WaitStrategies.noWait())
      

      5.8 WaitStrategies.join (CompositeWaitStrategy)

      WaitStrategies.join可以將多種等待策略組合起來,等待時間為多個策略的時間和。
      例如,join了exponentialWait和fixedWait:

      .withWaitStrategy(WaitStrategies.join(WaitStrategies.exponentialWait(100, 5, TimeUnit.SECONDS), 
          WaitStrategies.fixedWait(1, TimeUnit.SECONDS)))
      

      6 監聽器

      public class MyRetryListener<String> implements RetryListener {
      
         @Override
         public <String> void onRetry(Attempt<String> attempt) {
      
            // 第幾次重試,(注意:第一次重試其實是第一次調用)
             System.out.print("[retry]time=" + attempt.getAttemptNumber());
      
            // 距離第一次重試的延遲
             System.out.print("[retry]delay=" + attempt.getDelaySinceFirstAttempt());
      
            // 重試結果: 是異常終止, 還是正常返回
             System.out.print("[retry]hasException=" + attempt.hasException());
             System.out.print("[retry]hasResult=" + attempt.hasResult());
      
            // 是什么原因導致異常
            if (attempt.hasException()) {
                System.out.print("[retry]causeBy=" + attempt.getExceptionCause().toString());
            } else {
               // 正常返回時的結果
                System.out.print("[retry]result=" + attempt.getResult());
            }
      
            // bad practice: 增加了額外的異常處理代碼
              try {
                  String result = attempt.get();
                  System.out.print("rude get=" + result);
              } catch (ExecutionException e) {
                  System.err.println("this attempt produce exception." + e.getCause().toString());
              }
      
         }
      }
      

      posted on 2022-12-02 10:38  Chase_Hanky  閱讀(771)  評論(0)    收藏  舉報

      主站蜘蛛池模板: 亚洲精品自产拍在线观看动漫 | 国产福利高颜值在线观看| 下面一进一出好爽视频| 亚洲国产成人综合自在线| 日本熟妇XXXX潮喷视频| 午夜DY888国产精品影院 | 亚洲欧美偷国产日韩| 国产不卡一区二区精品| 国产精品三级一区二区三区| 国偷自产一区二区免费视频| 国产麻豆成人传媒免费观看| yyyy在线在片| 国产成人a在线观看视频| 99在线精品国自产拍中文字幕| 97成人碰碰久久人人超级碰oo| 欧美人与动牲猛交A欧美精品| 国产精品无码成人午夜电影| 色综合伊人色综合网站| 三级三级三级A级全黄| 亚洲国产成人精品av区按摩| 人妻中文字幕亚洲精品| 国产精品午夜福利资源| 99久久精品国产一区二区| 色狠狠一区二区三区香蕉| 亚洲成av人片天堂网| 在线免费观看亚洲天堂av| 陈巴尔虎旗| 久久精品久久黄色片看看| 国产成a人片在线观看视频下载| 无码伊人66久久大杳蕉网站谷歌| 亚洲第一福利网站在线观看| 国产精品午夜福利视频| 久久人人97超碰人人澡爱香蕉| 亚洲欧美在线观看品| 久久精品国产福利一区二区| 国产免费无遮挡吃奶视频| 激情久久av一区二区三区| 久久这里只有精品首页| 伊人久久大香线蕉av色婷婷色| 国产欧美在线观看一区| 国产涩涩视频在线观看|