基于fegin远程调用的重试功能

前言

        在微服务场景中,可能因为系统中网络抖动,导致调用超时或者失败, 按照我们分布式事务角度来看的话, 如果我们在业务中只调用了一次远程的服务查询(只去查询用户服务的某个信息),如果查询失败, 从而导致整个业务回滚, 这种代价是我们不想看到,所以我们就可以基于fegin的远程调用, 提高成功的可能性, 尽可能的避免回滚

来 我们上代码

        首先基于AOP注解的方式, 定义切面

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface FeignRetry {

    Backoff backoff() default @Backoff(); //定义重试机制

    int maxAttempt() default 3; //最大重试次数

    Class<? extends Throwable>[] include() default {} ;


}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Backoff {
    long delay() default 1000L; //第一次重试时间间隔

    long maxDelay() default 0L; //最大延迟时间

    double multiplier() default 0.0D;

}

 

@Aspect
@Slf4j
@Component
public class FeignRetryAspect {

    @Around("@annotation(com.yomahub.tlog.example.feign.inteferce.FeignRetry)")
    public Object retry(ProceedingJoinPoint joinPoint) throws Throwable {
        Method method = getCurrentMethod(joinPoint);
        FeignRetry feignRetry = method.getAnnotation(FeignRetry.class);

        RetryTemplate retryTemplate = new RetryTemplate();
        retryTemplate.setBackOffPolicy(prepareBackOffPolicy(feignRetry));
        retryTemplate.setRetryPolicy(prepareSimpleRetryPolicy(feignRetry));

        return retryTemplate.execute(arg0 -> {
                    int retryCount = arg0.getRetryCount();
                    log.info("Sending request method: {}, max attempt: {}, delay: {}, retryCount: {}",
                            method.getName(),
                            feignRetry.maxAttempt(),
                            feignRetry.backoff().delay(),
                            retryCount
                    );
                    return joinPoint.proceed(joinPoint.getArgs());
                },
                context -> {
                    //重试失败后执行的代码
                    log.info("我在重试了{}次后,我最终还是失败了======", context.getRetryCount());
                    return "failed callback";
                }
        );


    }

    private BackOffPolicy prepareBackOffPolicy(FeignRetry feignRetry) {
        if (feignRetry.backoff().multiplier() != 0) {
            ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
            backOffPolicy.setInitialInterval(feignRetry.backoff().delay());
            backOffPolicy.setMaxInterval(feignRetry.backoff().maxDelay());
            backOffPolicy.setMultiplier(feignRetry.backoff().multiplier());
            return backOffPolicy;
        } else {
            FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();
            fixedBackOffPolicy.setBackOffPeriod(feignRetry.backoff().delay());
            return fixedBackOffPolicy;
        }
    }


    private SimpleRetryPolicy prepareSimpleRetryPolicy(FeignRetry feignRetry) {
        Map<Class<? extends Throwable>, Boolean> policyMap = new HashMap<>();
        policyMap.put(RetryableException.class, true);  // Connection refused or time out
        policyMap.put(ClientException.class, true);     // Load balance does not available (cause of RunTimeException)
        if (feignRetry.include().length != 0) {
            for (Class<? extends Throwable> t : feignRetry.include()) {
                policyMap.put(t, true);
            }
        }
        return new SimpleRetryPolicy(feignRetry.maxAttempt(), policyMap, true);
    }

    private Method getCurrentMethod(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        return signature.getMethod();
    }
@FeignClient("tlog-logback-feign-provider")
public interface TLogFeignClient {

    @RequestMapping(value = "hi",method = RequestMethod.GET)
    @FeignRetry(maxAttempt = 6, backoff = @Backoff(delay = 500L, maxDelay = 20000L, multiplier = 4))
    public String sayHello(@RequestParam(value = "name") String name);


}

  • 18
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值