重试处理 - 重试模板

优质
小牛编辑
129浏览
2023-12-01

请注意 这个重试功能在Spring Batch 2.2.0里面退出,现在它是Spring Retry的一部分.

为了让这个进程更稳定,更小的失败性。有时它帮助自动重试一个失败的操作以防止它可能在后续的尝试成功。本质上,这种处理会导致误差。例如,远程调用网络服务或RMI服务失败是由于在短暂的数据更新后,网络故障或冻结异常aDeadLockLoserException.例如重试这种自动化操作,Spring Batch有重试操作的策略。
重试操作接口如下:

  1. public interface RetryOperations {
  2. <T> T execute(RetryCallback<T> retryCallback) throws Exception;
  3. <T> T execute(RetryCallback<T> retryCallback, RecoveryCallback<T> recoveryCallback)
  4. throws Exception;
  5. <T> T execute(RetryCallback<T> retryCallback, RetryState retryState)
  6. throws Exception, ExhaustedRetryException;
  7. <T> T execute(RetryCallback<T> retryCallback, RecoveryCallback<T> recoveryCallback,
  8. RetryState retryState) throws Exception;
  9. }

基本回调是一个简单的接口,允许您插入一些业务逻辑重试:

  1. public interface RetryCallback<T> {
  2. T doWithRetry(RetryContext context) throws Throwable;
  3. }

执行回调如果失败了(抛出异常),它会重试直至成功或者执行决定终止。在重试界面,有一些超载的操作方法,专门处理恢复各种用户实例。也可以在重试阶段,允许客户端和实现信息存储之间的调用(后面详细讨论)

最简单通用的实施RetryOperations就是Retry Template。就像这样

  1. RetryTemplate template = new RetryTemplate();
  2. TimeoutRetryPolicy policy = new TimeoutRetryPolicy();
  3. policy.setTimeout(30000L);
  4. template.setRetryPolicy(policy);
  5. Foo result = template.execute(new RetryCallback<Foo>() {
  6. public Foo doWithRetry(RetryContext context) {
  7. // Do stuff that might fail, e.g. webservice operation
  8. return result;
  9. }
  10. });

在这个例子中我们执行web服务调用和返回结果给用户。如果调用失败然后重试,直到超时。

重试上下文" class="reference-link">9.1.1 重试上下文

RetryCallback的方法参数是RetryContext.许多回调会简单地忽略上下文,但必要时它可以作为一个属性包为迭代的持续时间存储数据。

在同一线程中,如果一个嵌套在重试过程中, RetryContext会有一个母本。这个母本偶尔在存储数据用于调用和执行共享很有帮助

恢复回调" class="reference-link">9.1.2 恢复回调

当一个重试耗尽这个RetryOperations可以传递控制一个不同的回调,是恢复回调。要使用该功能的客户只是通过同样的方法回调在一起,例如:

  1. Foo foo = template.execute(new RetryCallback<Foo>() {
  2. public Foo doWithRetry(RetryContext context) {
  3. // business logic here
  4. },
  5. new RecoveryCallback<Foo>() {
  6. Foo recover(RetryContext context) throws Exception {
  7. // recover logic here
  8. }
  9. });

在这个模板决定终止之前如果业务逻辑没有执行成功,然后客户端有机会做一些交替处理通过恢复回调处理

无状态的重试" class="reference-link">9.1.3 无状态的重试

在一个简单的实例中,重试只是一个while循环,RetryTemplate可以不断尝试,直到成功或失败,RetryContext包含一些状态来确定是否重试或中止,但这种状态在堆栈上没有必要在任何时候地方存储,所以我们称之为无状态的重试,无状态和有状态重试之间的区别是包含在实施RetryPolicy中(RetryTemplate可以同时处理),在一个无状态的重试,执行回调总是在同一线程上耗尽而失败

状态性重试" class="reference-link">9.1.4 状态性重试

有一些需要特别考虑的是,当失败引起事务资源无效,这并不适用于一个简单的远程调用,因为没有事务资源(通常),但它有时适用于数据库更新,尤其是使用Hibernate,这个案例中,我们重新抛出这个异常,我们称之为立即失效,这样的话,事物资源可以回滚,我们可以启用一个新的。

在这些情况下无状态重试还不够好,因为re-throw和回滚必然涉及离开RetryOperations.execute()方法和潜在损失的上下文堆栈。为了避免失去它我们必须引入存储策略提升了堆栈并把它(至少)放在堆存储中,为此Spring Batch提供了一个存储策略RetryContextCache可以注入RetryTemplate。内存中有RetryContextCache默认的实现,使用一个简单的Map。多个进程的高级用法在集群环境中也会考虑实现集群缓存的RetryContextCache(不过,在集群环境中这可能是过度)。

RetryOperations的责任之一就是在一个执行新任务时候识别错误操作(通常是包裹在一个新的事务)。为了使它更方便,Spring Batch提供抽象的RetryStateRetryOperations结合特殊执行操作方法

识别错误的操作方法是通过识别跨多个调用的重试。辨别出这个状态,用户可以提供RetryState对象返回一个唯一键识别项。标识符用作RetryContextCache的一个关键。

警告
实现Object的equals方法和hashCode方法要非常小心,关键是在返回重试状态。最好的建议是使用一个业务主键来标识这个项目,在JMS 消息的message Id可以使用的情况下。

当重试停止也有选择以不同的方式处理失败的项,而不是调用RetryCallback(假定现在可能失败)。就像在无状态的情况下,这个选项是RecoveryCallback提供的,也可以用越过RetryOperations的执行方法提供。

重试与否实际上是委托给一个普通的RetryPolicy,所以通常的使自己关心的限制和超时是可以注入的(见下文)。