起源
库存同步因为店铺-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次数会抛异常出来,如果有循环可能造成影响