1 重试注解
(1)定义重试注解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RetryAnnotation {
int retryTimes() default 0 ;
/**
* 重试策略
* @return
*/
MidBackoff backoff() default @MidBackoff();
}
(2)重试切面
@RefreshScope
@Component
@Aspect
@Slf4j
public abstract class RetryAspect {
@Resource
private RetryTemplate retryTemplate;
@Value("${system.config.cluster:normal}")
private String env;
@Value("${myj.env.groupId}")
private String groupId;
@Value("${myj.env.cluster}")
private String envConfig;
@Pointcut("@annotation(com.sr.bizmid.tradeCore.common.annotation.RetryAnnotation)")
public void pointCut() {
}
@Around("pointCut() && @annotation(retryAnnotation)")
public Object process(ProceedingJoinPoint joinPoint, RetryAnnotation retryAnnotation) throws Throwable {
AtomicReference<Object> proceed = new AtomicReference<>();
Signature signature = joinPoint.getSignature();
String name = signature.getName();
Class targetClass = signature.getDeclaringType();
final Object[] args = joinPoint.getArgs();
try {
retryTemplate.execute(context -> {
try {
proceed.set(joinPoint.proceed());
} catch (Exception e) {
log.error("RetryAspect retryError className:{} method:{} args:{}",targetClass.getName(),name, JSON.toJSONString(args),e);
throw e;
}
return null;
});
} catch (Exception e) {
log.error("RetryAspect retryFinishError className:{} method:{} args:{}",targetClass.getName(),name,JSON.toJSONString(args),e);
//加入重试表重试
saveRetryRecord(joinPoint, retryAnnotation);
throw new TRetailSystemException(TradeBaseErrorCode.TRADE_CORE_RETRY_ASPECT_ERROR,e);
}
return proceed.get();
}
private void saveRetryRecord(ProceedingJoinPoint joinPoint, RetryAnnotation retryAnnotation){
try {
Date date = new Date();
BizRetry bizRetry = new BizRetry();
bizRetry.setCreateTime(date);
bizRetry.setUpdateTime(date);
bizRetry.setOperableTime(date);
bizRetry.setStatus((byte) 0);
bizRetry.setIsDeleted(isAbandon() ? (byte) 1 : (byte) 0);//加上开关
bizRetry.setRetriedCount(0);
bizRetry.setMethodName(joinPoint.getSignature().getName());
bizRetry.setClassName(joinPoint.getSignature().getDeclaringType().getName());
MidBackoff backoff = retryAnnotation.backoff();
BizRetry.MidBackoff midBackoff = new BizRetry.MidBackoff();
midBackoff.setCount(backoff.count());
midBackoff.setDelay(backoff.delay());
midBackoff.setMultiplier(backoff.multiplier());
bizRetry.setBackoff(midBackoff);
int delay = backoff.delay();
if (backoff.multiplier() > 0d) {
delay = (int) ((double) delay * backoff.multiplier());
}
bizRetry.setOperableTime(add(date, Calendar.SECOND, delay));
Object[] args = joinPoint.getArgs();
List<String> argsList = new ArrayList<>(args.length);
List<String> types = new ArrayList<>();
Class[] parameterTypes = ((MethodSignature)joinPoint.getSignature()).getMethod().getParameterTypes();
for (Class clazz : parameterTypes) {
types.add(clazz.getName());
}
for (Object arg : args) {
argsList.add(JSON.toJSONString(arg));
}
// 参数列表类型
bizRetry.setArgsTypes(JSON.toJSONString(types));
// 参数
bizRetry.setArgs(JSON.toJSONString(argsList));
// 保存重试记录
saveRetryRecord(bizRetry);
}catch (Throwable t){
LoggerUtils.fmtError(log,t,"saveRetryRecord新增重试记录异常");
}
}
/**
* 返回true拦截,false不拦截
* @return
*/
private boolean isAbandon() {
boolean result;
try {
String appId = TsrSpringContextAware.getApplicationContext().getEnvironment().getProperty("tsf_group_id");
// 匹配过滤的环境
result = groupId.equals(appId) && envConfig.equals(env);
} catch (Exception e) {
result = false;
}
return result;
}
private Date add(Date date, int calendarField, int amount) {
if (date == null) {
throw new IllegalArgumentException("The date must not be null");
}
Calendar c = Calendar.getInstance();
c.setTime(date);
c.add(calendarField, amount);
return c.getTime();
}
public abstract void saveRetryRecord(BizRetry bizRetry);
}
(3)RPC 调用使用重试注解
@RetryAnnotation(backoff = @MidBackoff(count = 5,multiplier = 1,delay = 30))
public void writeOFFCoupon(String orderNo, String uid, Long rootSaasId, Long saasId, String userName, List<String> codes){
OperateCouponsRequest operateCouponsRequest = new OperateCouponsRequest();
operateCouponsRequest.setRequestId(uid + System.currentTimeMillis());
operateCouponsRequest.setBizId(rootSaasId);
operateCouponsRequest.setSubSaasId(saasId);
operateCouponsRequest.setOperator(userName);
operateCouponsRequest.setFunc(OperateCouponFuncEnum.WRITE_OFF.getFunc());
operateCouponsRequest.setCodes(codes);
operateCouponsRequest.setUserId(uid);
operateCouponsRequest.setUseSceneId(UseChannelEnum.ONLINE.getChannel().toString());
operateCouponsRequest.setUseTransactionId(orderNo);
HttpResult<Boolean> httpResult;
try {
log.info("调用核销优惠券请求入参:{}", JSON.toJSONString(operateCouponsRequest));
httpResult = couponClient.operateCoupons(operateCouponsRequest);
log.info("调用核销优惠券请求response:{}", JSON.toJSONString(httpResult));
}catch (Exception e) {
throw new TRetailRpcResultException(TradeRpcErrorCode.TRADE_CALL_COUPON_ERROR, e);
}
if (!httpResult.isSuccess() || httpResult.getData() == null) {
throw new TRetailRpcResultException(TradeRpcErrorCode.TRADE_CALL_COUPON_ERROR);
}
}