转载

spring-retry的简单模型整理

在业务系统中,经常会遇到进行业务重试的场景,当一个执行方法失败时,可能需要进行几次重试,如果重试时成功了,仍然认为业务是正确的。否则则throw相应的异常。这种通用的重试场景则可以使用标准的第三方重试库来完成,以避免自己在业务代码中写类似while try 的代码。同时,因为重试的条件以及处理的逻辑均不太一样,通过一个标准的重试库来完成此操作,也是很有必要的。

本文描述了spring提供的重试库spring-retry,通过提取相应的概念模型,了解其工作原理以及执行机制.

版本:1.2.2.RELEASE

会使用到的注释

Retryable

用于标识一个可以进行重试的方法,即一个方法如果需要在throw异常之后进行重试,则可以使用此注解进行标记.同时,此注解上标识了可以进行重试的一些条件以及次数信息。

Backoff

此标识一个方法在进行下一次重试时,需要暂停的一些手法以及参数信息,比如sleep多少秒,或者是是在一个区间范围内sleep。

Recover

此标识当一个方法执行多次都失败之后,进行的一个failback处理。

主要的业务接口

RetryContext

重试上下文,即维护了整个重试周期中相应调用对象,调用次数,以及在调用过程中的异常对象等,其它接口均从此对象中获取相应的数据.

RetryOperations

封装了一个主要可重试操作,可以理解为进行主要逻辑操作的template对象。

RetryPolicy

与@Backoff相对应的一个接口,用于在整个重试逻辑中,处理何时该重试,以及控制相应的重试上下文信息。

RetryListener

监听器,用于在重试过程中,对开始,重试出错,结束时进行拦截操作。默认情况下,此类为null,即无作用。

RetryCallback

简单的重试回调对象,用于封装原来的可重试方法,将整个操作统一使用callback来表示,以隔离相应的实现。

RecoveryCallback

与@Recover相对应,即最终进行failback的回调对象.

整个spring-retry的执行逻辑均封装在RetryTemplate这个类中,然后在外部通过RetryConfiguration来配置一些额外的业务接口信息,最终形成一个bean拦截器,通过拦截bean的调用来完成重试的处理.

一个简单的执行逻辑(以无状态重试为例)

整个逻辑参照于类RetryTemplate#doExecute方法,其中 recoveryCallback对象为null,即无failback. state为null,即不是有状态的重试.

  1. 创建想重试上下文 RetryContext ,即为当前执行准备好相应的数据对象
  2. 启动相应的拦截器 RetryListener, 以支持在进行实际调用前进行相应的判断,以判断是否应该继续执行操作
  3. 启动可重试判定 RetryPolicy,判定的条件包括当前执行次数,以及相应的异常是否在期望异常体系之内。
  4. 执行实际的业务逻辑 RetryCallback,如果成功则直接返回
  5. 业务执行失败,上下文 RetryContext 补充相应的异常数据
  6. 同时拦截器 启动失败时拦截回调. RetryListener, 此时的失败回调是void,即仅起到通知作用
  7. 在需要进行下一次重试的基础之上(即还会进行重试), 启动 RetryPolicy 重试策略,即准备相应的间隔sleep处理
  8. 在所有重试均结束时,直接Throw最后一次执行异常.
  9. 完成整个重试逻辑,拦截器 RetryListener 进行onClose回调,即在整个重试体系结束前进行通知回调.

实际业务场景举例

在实际的业务场景当中,对于一个业务方法 doBusiness(), 我们期望对此方法进行重试操作,在调用此方法时,如果throw了一个TimeoutException,则进行重试,重试次数为3,每次重试时间隔1秒。

对于这个业务场景,则相应的配置则如下参考所示:

@Retryable(maxAttempts=3, backoff=@Backoff(1000))
public void doBusiness() {
    //do your business
}

后注

其实spring-retry的整个概念还是很简单的,只不过考虑场景太多,以至于一些源码理解上偏麻烦,但对于整个重试场景来说,spring-retry在模型和接口上的整理还是很值得参考。在一个简单的业务场景中,可以自己发明一个小轮子来完成类似的事务。在一些类似的设计场景,也可以考虑类似的方法和实现.

原文  https://www.iflym.com/index.php/code/201805070001.html
正文到此结束
Loading...