起源
庫存同步因爲店鋪-sku-spu-庫存進行笛卡爾積,同步總數龐大,可能一天輪詢一次。可能因爲請求過於頻繁,所以偶爾請求會報錯,內容如下:
無法卡定時任務
- 有的定時任務,比如生成發票這種,如果不成功,可以卡定時任務。原因是操作數量小,內容可控(數據可控,系統內可更改),短時間卡頓影響不大
- 庫存同步定時任務,因爲多次笛卡爾積,涉及到庫存量的問題,所以無法卡定時任務,不論結果如何,必須跑下去,此庫存同步失敗了,需進行後續的庫存同步
造成後果
同步失敗的庫存,造成庫存同步延遲,可能到第二天才會重試
解決方式
1.這是什麼
百度得知這東西全名叫guava-retrying
2.java版本
找到版本50,對應jdk1.6,OK,服務器JDK版本1.7,可以正常用
Retry的百度代碼
Callable<Integer> task = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
return 2;
}
};
Retryer<Integer> retryer = RetryerBuilder.<Integer>newBuilder()
.retryIfResult(Predicates.<Integer>isNull())//爲空就retry
.retryIfResult(Predicates.equalTo(2))//爲2就retry
.retryIfExceptionOfType(IOException.class)//異常是IO異常就retry
.withStopStrategy(StopStrategies.stopAfterAttempt(3))//最多retry3次
.withWaitStrategy(WaitStrategies.fixedWait(3, TimeUnit.SECONDS))//重試等3秒
.build();
try {
retryer.call(task);
} catch (ExecutionException e) {
e.printStackTrace();
} catch (RetryException e) {
e.printStackTrace();
}
遇到的問題
retryIfResult現有的不滿足要求,我要的是對象裏面的字段值如果是false就retry,百度找不到解法,沒辦法看源碼
retryIfResult
這句可以看出retryIfResult裏面應該做了判斷用於是否retry
可以看到這裏調用了傳入的Predicate的對象apply返回值,所以我們應該做個Predicate,裏面包含apply方法,讓它的返回值爲true就會進行重試了
Predicates.equalTo(2)
這句可以看出Predicates應該是個工具類,用於創造Predicate對象,那就參考一下內部的Predicate,可以找到一個比較像的:
特別簡單,做個枚舉單例就可以了
####最終效果
這裏注意到是否成功進行了取反,因爲我這裏請求成功的情況會返回true,不成功返回false。這種情況,希望不成功的結果進行重試,所以要取反
最終效果
Retryer<EsbPlatformResultVO> retryer = RetryerBuilder.<EsbPlatformResultVO>newBuilder()
.retryIfException()
.retryIfResult(CreateFaciltiyPredicate.INSTANCE)
.withWaitStrategy(WaitStrategies.fixedWait(5, TimeUnit.SECONDS))
.withStopStrategy(StopStrategies.stopAfterAttempt(3))
.build();
EsbPlatformResultVO resultVO1=new EsbPlatformResultVO();
try{
resultVO1 = retryer.call(new CreateFacilityTask());
}catch (Exception e){
resultVO1.setSuccess(false);
resultVO1.setMessage("XXX");
}
public class CreateFacilityTask implements Callable<EsbPlatformResultVO> {
public CreateFacilityTask(){
}
@Override
public EsbPlatformResultVO call() throws Exception {
EsbPlatformResultVO resultVO1 = doSomething();
//...此處代碼按照自己需求來寫
return resultVO1;
}
}
注意點:retryer.call要用try…catch包圍,不然超過了retry次數會拋異常出來,如果有循環可能造成影響