對於開發過網絡應用程序的程序員來講,重試並不陌生,因爲網絡的擁堵和波動,此刻不能訪問服務的請求,也許過一小段時間就能夠正常訪問了。好比下面這段給某個手機號發SMS的僞代碼: git
// 發送SMS 程序員
public boolean sendSMS(String phone, String content) github
{ spring
int retryTimes = 3; 網絡
for(int i=0; i<=3; i++) ide
{ 工具
try ui
{ 開發
boolean result = doSomething(phone, content); it
// 發送成功直接返回
if(result == true)
{
return true;
}
}
catch(IOException e)
{
// 多是網絡問題致使IOException,因此咱們繼續重試
logger.error("send sms error", e);
}
catch(Exception e)
{
// 未知異常,與網絡無關,有多是代碼出現問題,這個時候重試沒用,咱們直接返回false logger.error("unknown exception", e); return false;
}
}
return false;
}
// 給某人發短信
private boolean doSomething(String phone, String content)
{
}
這段代碼有什麼問題呢?看起來很醜,爲了實現重試邏輯,各類if-else,各類try-catch。重試邏輯太簡單,只是控制了重試次數,並無控制2次重試之間的時間間隔。由於重試代碼與業務代碼耦合在一塊兒,因此看起來很複雜。
試想若是咱們要改變重試邏輯:好比咱們但願每次重試事後,隨機等待一段時間後再重試;好比咱們但願重試次數不超過10次,並且總共的重試時間不超過1分鐘;好比咱們但願每次重試的時候,都給咱們監控系統發一條消息...隨着重試邏輯的不斷變化,上面代碼會愈來愈複雜。並且重試邏輯,實際上是各個模塊是差異不大的。
最近遇到2個開源項目,都是將重試代碼封裝成專門的工具,方便使用,好比guava-retrying和spring-retry。後面的文章,會介紹下如何使用guava-retrying。下面這段代碼使用的是guava-retrying,明顯能夠感到代碼變簡單了。
public boolean sendSMS(final String phone, final String content)
{
Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder() .retryIfResult(Predicates.equalTo(false)) // 返回false時重試 .retryIfExceptionOfType(IOException.class) // 拋出IOException時重試 .withWaitStrategy(WaitStrategies.fixedWait(200, TimeUnit.MILLISECONDS)) // 200ms後重試
.withStopStrategy(StopStrategies.stopAfterAttempt(3)) // 重試3次後中止
.build();
try {
return retryer.call(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return doSomething(phone, content);
}
});
} catch (Exception e) {
return false;
}
}
這2個項目github地址是:
https://github.com/rholder/guava-retrying
https://github.com/spring-projects/spring-retry guava-retrying
博文以下:
guava-retrying重試工具庫: 何時重試
guava-retrying重試工具庫: 何時終止
guava-retrying重試工具庫: 隔多長時間重試
guava-retrying重試工具庫: 阻塞策略BlockStrategy
guava-retrying重試工具庫: AttemptTimeLimiter
guava-retrying重試工具庫: RetryListener guava-retrying重試工具庫:
Retryer.call()使用注意事項