為什么要使用重試利器Retryer
在實際開發中我們經常會遇到需要輪詢查詢一個接果,實現輪詢的方式有很多種,我們經常要寫許多代碼,有時還會怕寫出的代碼有bug,如果已經有輪子了,我們就沒必要重復造輪子了,畢竟時間有限,我們要掙錢。
github上開源的重試利器: https://github.com/rholder/guava-retrying
此retry是結合了Callable接口來實現,重試功能的,話不多說,直接上碼。
重試利器maven配置
<dependency> <groupId>com.github.rholder</groupId> <artifactId>guava-retrying</artifactId> <version>2.0.0</version> </dependency>
重試利器示例
1.如果想重試幾次就結束輪詢的話,可參考如下代碼
package com.example.guava; 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.google.common.base.Predicates; import java.io.IOException; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; /** * @author: GuanBin * @date: Created in 下午4:30 2019/11/3 */ public class RetryTest { public static void main(String[] args) { //callable是定義具體的業務操作,並返回該操作結果的返回值 Callable<Boolean> callable = new Callable<Boolean>() { public Boolean call() throws Exception { return true; // do something useful here } }; //定義retryer,指定輪詢條件,及結束條件 Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder() .retryIfResult(Predicates.<Boolean>isNull()) .retryIfExceptionOfType(IOException.class) .retryIfRuntimeException() .withStopStrategy(StopStrategies.stopAfterAttempt(3)) .build(); try { retryer.call(callable); } catch (RetryException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } }
retryer的條件是,callable的返回值是null或者有io異常或者運行時異常,則進行重試,重試次數為3次;
2.如果想以每隔一段時間的頻率重試可參考如下代碼
Retryer<TaskResult> getExecutionStatusRetryer = RetryerBuilder.<TaskResult>newBuilder() .withWaitStrategy(WaitStrategies.fixedWait(5, TimeUnit.SECONDS)) .retryIfResult(r -> !Constants.completeStatus.contains(r.getStatus())) .withStopStrategy(StopStrategies.neverStop()) .build();
WaitStrategies定義等待策略:示例是5秒一次就會輪詢一次call的實現()
StopStrategies是定義停止輪詢策略的,StopStrategies.neverStop() 若滿足輪詢條件的話,會一直進行重試下去
3.創建一個永久重試的重試器,在每次重試失敗后以遞增的指數退避間隔等待,直到最多5分鍾。 5分鍾后,每隔5分鍾重試一次。
Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder() .retryIfExceptionOfType(IOException.class) .retryIfRuntimeException() .withWaitStrategy(WaitStrategies.exponentialWait(100, 5, TimeUnit.MINUTES)) .withStopStrategy(StopStrategies.neverStop()) .build();
若第一次重試是100毫秒后重試,若進行第二次則是增加到200毫秒進行重試,依次類推,知道達到5分鍾的上限,之后按照5分鍾一次的頻率進行重試
有興趣的可參考 指數回退:https://en.wikipedia.org/wiki/Exponential_backoff
4.創建一個永久重試的重試器,在每次重試失敗后以遞增的退避間隔等待,直到最多2分鍾。 2分鍾后,每隔2分鍾重試一次
Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder() .retryIfExceptionOfType(IOException.class) .retryIfRuntimeException() .withWaitStrategy(WaitStrategies.fibonacciWait(100, 2, TimeUnit.MINUTES)) .withStopStrategy(StopStrategies.neverStop()) .build();
與指數等待策略類似,FibonacciWaitStrategy遵循的模式是每次嘗試失敗后等待時間增加。
FibonacciWaitStrategy是用斐波那契數列來計算等待時間,而不是指數函數。根據目前實踐中發現,fibonacciwaitstrategy可能比指數waitstrategy有更好的性能和更好的吞吐量-至少根據不同回退算法在不同重播概率下的性能比較。