1. 程式人生 > >重試利器之Guava-Retryer

重試利器之Guava-Retryer

Guava Retrying是一個靈活方便的重試元件,包含了多種的重試策略,而且擴充套件起來非常容易。

用作者的話來說:

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 風格的重試方式真的很方便。

程式碼示例

  • 引入Guava-retry
<guava-retry.version>2.0.0</guava-retry.version>
<dependency>
      <groupId>com.github.rholder</groupId>
      <artifactId>guava-retrying</artifactId>
      <version>${guava-retry.version}</version>
</dependency>
  • 定義實現Callable介面的方法,以便Guava retryer能夠呼叫
package org.java.base.retry;

import java.io.IOException;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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;

public class RetryTest {
 private static final Logger logger = LoggerFactory.getLogger(RetryTest.class);
 public static void main(String[] args){ 
 Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
 .retryIfResult(Predicates.<Boolean>isNull())// 設定自定義段元重試源
 .retryIfExceptionOfType(Exception.class)// 設定異常重試源
 .retryIfRuntimeException()// 設定異常重試源
 .withStopStrategy(StopStrategies.stopAfterAttempt(5))// 設定重試5次,同樣可以設定重試超時時間
 .withWaitStrategy(WaitStrategies.fixedWait(5L, TimeUnit.SECONDS))// 設定每次重試間隔,5秒
 .build();
 try {
 retryer.call(new Callable<Boolean>() {
 int i = 0;

 @Override
 public Boolean call() throws Exception {
 i++;
 logger.info("第{}次執行!", i);
 // do something
 if (i<6) {// 模擬錯2次
 logger.info("模擬執行失敗!");
 throw new IOException("異常");
 }
 logger.info("模擬執行成功!");
 return true; 
 }
 });
 } catch (RetryException e) {
 logger.info("超過重試次數", e);
 } catch (ExecutionException e) {
 logger.info("重試框架異常", e);
 }
 }


}

簡單三步就能使用Guava Retryer優雅的實現重調方法。
接下來對其進行詳細說明:

  • RetryerBuilder是一個factory建立者,可以定製設定重試源且可以支援多個重試源,可以配置重試次數或重試超時時間,以及可以配置等待時間間隔,建立重試者Retryer例項。
  • RetryerBuilder的重試源支援Exception異常物件 和自定義斷言物件,通過retryIfException 和retryIfResult設定,同時支援多個且能相容。
  • retryIfException,丟擲runtime異常、checked異常時都會重試,但是丟擲error不會重試。
  • retryIfRuntimeException只會在拋runtime異常的時候才重試,checked異常和error都不重試。
  • retryIfExceptionOfType允許我們只在發生特定異常的時候才重試,比如NullPointerException和IllegalStateException`都屬於runtime異常,也包括自定義的error

如:

.retryIfExceptionOfType(Error.class)// 只在丟擲error重試

當然我們還可以在只有出現指定的異常的時候才重試,如:

.retryIfExceptionOfType(IllegalStateException.class)  
.retryIfExceptionOfType(NullPointerException.class)

或者通過Predicate實現

.retryIfException(Predicates.or(Predicates.instanceOf(NullPointerException.class),  
                Predicates.instanceOf(IllegalStateException.class)))

retryIfResult可以指定你的Callable方法在返回值的時候進行重試,如

// 返回false重試 
.retryIfResult(Predicates.equalTo(false))  
//以_error結尾才重試 
.retryIfResult(Predicates.containsPattern("_error$"))  

執行結果如下:

1528257618(1)

主要介面及策略介紹:

Attempt:一次執行任務;

AttemptTimeLimiter:單次任務執行時間限制(如果單次任務執行超時,則終止執行當前任務);

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 :複合時長等待策略;

參考資料:

http://blog.csdn.net/aitangyong/article/details/53894997

https://segmentfault.com/a/1190000006918410

http://blog.csdn.net/aitangyong/article/details/53886293

http://baijiahao.baidu.com/s?id=1575327487081031&wfr=spider&for=pc

http://www.cnblogs.com/jianzh5/p/6651799.ht