接口调用失败重试方案


背景

在项目开发中,有时候会出现接口调用失败,本身调用又是异步的,如果是因为一些网络问题请求超时,总想可以重试几次把任务处理掉。

一些RPC框架,比如dubbo都是有重试机制的,但是并不是每一个项目都会使用dubbo框架,常规的小项目有时候直接使用http进行不同项目之间的交互。

思路

使用spring aop和自定义注解来,建立一套重试机制。

根据切入点和自定义注解,来完成重试工作。

定义一个自定义注解

package com.it.ssm.annotation;

import org.springframework.stereotype.Component;

import java.lang.annotation.*;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface RetryProcess {
    //重试的次数
    int value() default 1;
}

定义一个切面

package com.it.ssm.annotation;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint;
import org.springframework.stereotype.Component;

import java.util.concurrent.atomic.AtomicInteger;

@Aspect
@Component
public class AspectExceptionInterceptor {
    private  final Logger logger = LoggerFactory.getLogger(this.getClass());
    private AtomicInteger atomicInteger = new AtomicInteger(0);

    @AfterThrowing(pointcut=("execution(* com.it.ssm..*(..)) && @annotation(com.it.ssm.annotation.RetryProcess)"))
    public void tryAgain(JoinPoint point) {
        try {
            Object object = point.getTarget();
            MethodSignature methodSignature = (MethodSignature) point.getSignature();
            RetryProcess retryProcess = methodSignature.getMethod().getAnnotation(RetryProcess.class);

            if (atomicInteger.intValue() < retryProcess.value()) {
                int i = atomicInteger.incrementAndGet();
               
                // 阻塞i秒后再进行重试,如果网络问题立即重试失败几率非常大所以建议阻塞一下再试
                Thread.sleep(1000 * i);
                
                logger.info("开始重试第" + i + "次");
                MethodInvocationProceedingJoinPoint methodPoint = ((MethodInvocationProceedingJoinPoint) point);
                // 再次调用方法
                methodPoint.proceed();
            }
        } catch (Throwable throwable) {
            // 捕获到异常后再次重试
            tryAgain(point);
        }
    }
}

测试

@RetryProcess(value = 3)
@RequestMapping("/testException")
public void testException() throws Exception {
    // 这里为了方便测试手动抛一个异常,实际此处应该是调用接口逻辑
    throw new RuntimeException("测试重试异常");
}

控制台结果

在这里插入图片描述

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值