外部接口调用失败重试

1 篇文章 0 订阅

第三方接口调用失败重试

规则
  1. 第三方接口调用失败后,相隔3秒后后重试;
  2. 若再次失败则相隔5秒重试,后续不再重试。
代码
@MyRetry
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyRetry {

    int retryTimes() default 0;

    int[] retrySecond() default {};

}
MyRetryFactory
public class MyRetryFactory {

    public static <T> T getRetryServiceProxy(T realObj) {
        Class<?>[] realIntfs = realObj.getClass().getInterfaces();
        Object proxyInstance = Proxy.newProxyInstance(MyRetryFactory.class.getClassLoader(), realIntfs,
                new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                // 接口方法上是否有@MyRetry
                if (method.isAnnotationPresent(MyRetry.class)) {
                    MyRetry myRetry = method.getDeclaredAnnotation(MyRetry.class);
                    int retryTimes = myRetry.retryTimes();
                    int[] retrySeconds = myRetry.retrySecond();

                    MyRetryTemplate myRetryTemplate = new MyRetryTemplate() {
                        @Override
                        public Object retry() throws Exception {
                            Object obj = method.invoke(realObj, args);
                            if (obj instanceof ResponseResult) {
                                // 网络异常,第三方接口也会返回结果,判断code是否等于0,决定是否重试
                                ResponseResult responseResult = (ResponseResult) obj;
                                if (responseResult == null || 	 (!"0".equals(responseResult.getCode()))) {
                                    if (responseResult == null) {
                                        throw new RuntimeException("接口返回对象为空");
                                    } else {
                                        throw new RuntimeException(responseResult.getMsg());
                                    }
                                }
                            }
                            return obj;
                        }
                    }.setRetryTimes(retryTimes).setRetrySeconds(retrySeconds);

                    // 先执行方法一次,再异步重试
                    try {
                        return myRetryTemplate.executeOnce();
                    } catch(Exception e) {
                        myRetryTemplate.executeAsync();
                    }
                    return null;
                } else {
                    return method.invoke(realObj, args);
                }
            };

        });

        return (T) proxyInstance;
    }
}
MyRetryTemplate
public abstract class MyRetryTemplate {

    private int retryTimes = 0;

    private int[] retrySeconds = {};

    public abstract Object retry() throws Exception;

    public Object executeOnce() throws Exception {
        System.out.println("第一次执行...");
        return retry();
    }

    public Object execute() {
        System.out.println("重试" + retryTimes + "次-分别相隔" + Arrays.toString(retrySeconds) + "秒");
        for (int i = 0; i < retryTimes; i++) {
            try {
                System.out.println(retrySeconds[i] + "s后准备第[" + (i + 1) + "]次重试!");
                Thread.sleep(1000 * retrySeconds[i]);
                return retry();
            } catch (Exception e) {
                System.out.println("重试失败:" + e);
            }
        }
        return null;
    }

    public void executeAsync() {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                execute();
            }
        });
        thread.start();
    }

    public MyRetryTemplate setRetryTimes(int retryTimes) {
        this.retryTimes = retryTimes;
        return this;
    }

    public MyRetryTemplate setRetrySeconds(int[] retrySeconds) {
        this.retrySeconds = retrySeconds;
        return this;
    }
}
ResponseResult
private String code;
private String msg;
// 省略getter/setter方法
ThirdCallService
@MyRetry(retryTimes = 2, retrySecond = {3, 5})
ResponseResult push();
ThirdCallServiceImpl
@Override
public ResponseResult push() {
    System.out.println("push()");
    ResponseResult responseResult = new ResponseResult();
    responseResult.setCode("-1");
    responseResult.setMsg("连接超时,网络异常");
    return responseResult;
}
Tester
ThirdCallService thirdCallService = new ThirdCallServiceImpl();
ThirdCallService thirdCallServiceProxy = MyRetryFactory.getRetryServiceProxy(thirdCallService);
thirdCallServiceProxy.push();
System.out.println("=============================");
结果
第一次执行...
push()
=============================
重试2-分别相隔[3, 5]3s后准备第[1]次重试!
push()
重试失败:java.lang.RuntimeException: 连接超时,网络异常
5s后准备第[2]次重试!
push()
重试失败:java.lang.RuntimeException: 连接超时,网络异常
总结
1. 符合模板方法模式。因为要重试几次,所以需要循环,循环总体逻辑一致,但是要调用的外部接口有很多。
2. 第一次正常调用接口返回结果,失败重试n次采用异步调用。
3. 采用JDK的动态代理。调用每个外部接口时,统一交由代理类实现总体重试规则代码。
4. 接口标注注解,来区分外部接口是否需要重试。
   代理类可依照该注解,分别执行需要重试和不需要重试的逻辑,做到统一区分。
5. 外部接口一般异常(如网络异常)返回的对象也会有值(code,msg),code不为成功代号需要纳入重试机制。
  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值