93 - 实战之通用的接口幂等框架(分析篇)

2021-11-01  本文已影响0人  舍是境界

本文我们来实战一个新的项目,开发一个通用的接口幂等框架。跟限流框架一样,我们还是分为分析、设计、实现三个部分。

需求场景

  1. 第一种处理方式是,调用方访问公共服务平台接口超时时,返回清晰明确的提醒给用户,告知执行结果未知,让用户自己判断是否重试。不过,你可能会说,如果用户看到了超时提醒,但还是重新发起了操作,比如重新发起了转账、充值等操作,那该怎么办呢?实际上,对这种情况,技术是无能为力的。因为两次操作都是用户主动发起的,我们无法判断第二次的转账、充值是新的操作,还是基于上一次超时的重试行为。
  2. 第二种处理方式是,调用方调用其他接口,来查询超时操作的结果,明确超时操作对应的业务,是执行成功了还是失败了,然后再基于明确的结果做处理。但是这种处理方法存在一个问题,那就是并不是所有的业务操作,都方便查询操作结果。
  3. 第三种处理方式是,调用方在遇到接口超时之后,直接发起重试操作。这样就需要接口支持幂等。我们可以选择在业务代码中触发重试,也可以将重试的操作放到 Feign 框架中完成。因为偶尔发生的超时,在正常的业务逻辑中编写一大坨补救代码,这样做会影响到代码的可读性,有点划不来。当然,如果项目中需要支持超时重试的业务不多,那对于仅有几个业务,特殊处理一下也未尝不可。但是,如果项目中需要支持超时重试的业务比较多,我们最好是把超时重试这些非业务相关的逻辑,统一在框架层面解决

需求分析

///////// 使用方式一: 在业务代码中处理幂等 ////////////
// 接口调用方
Idempotence idempotence = new Idempotence();
String idempotenceId = idempotence.createId();
Order order = createOrderWithIdempotence(..., idempotenceId);
// 接口实现方
public class OrderController {
  private Idempotence idempontence; // 依赖注入
  
  public Order createOrderWithIdempotence(..., String idempotenceId) {
    // 前置操作
    boolean existed = idempotence.check(idempotenceId);
    if (existed) {
      // 两种处理方式:
      // 1. 查询order,并且返回;
      // 2. 返回duplication operation Exception
    }
    idempotence.record(idempotenceId);
        
    //...执行正常业务逻辑
  }
  
  public Order createOrder(...) {
    //...
  }
}
///////// 使用方式二:在框架层面处理幂等 //////////////
// 接口调用方
Idempotence idempotence = new Idempotence();
String idempotenceId = idempotence.createId();
//...通过feign框架将幂等号添加到http header中...
// 接口实现方
public class OrderController {
  @IdempotenceRequired
  public Order createOrder(...) {
    //...
  }
}
// 在AOP切面中处理幂等
@Aspect
public class IdempotenceSupportAdvice {
  @Autowired
  private Idempotence idempotence;
@Pointcut("@annotation(com.xzg.cd.idempotence.annotation.IdempotenceRequired)")
  public void controllerPointcut() {
  }
  @Around(value = "controllerPointcut()")
  public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
    // 从HTTP header中获取幂等号idempotenceId
    
    // 前置操作
    boolean existed = idempotence.check(idempotenceId);
    if (existed) {
      // 两种处理方式:
      // 1. 查询order,并且返回;
      // 2. 返回duplication operation Exception
    }
    idempotence.record(idempotenceId)
    
    Object result = joinPoint.proceed();    
    return result;
  }
}

小结

上一篇 下一篇

猜你喜欢

热点阅读