Skip to content

Latest commit

 

History

History
131 lines (110 loc) · 6.3 KB

README.md

File metadata and controls

131 lines (110 loc) · 6.3 KB

spring retry and guava retry demo

从spring retry 官方copy: To make processing more robust and less prone to failure, it sometimes helps to automatically retry a failed operation, in case it might succeed on a subsequent attempt. Errors that are susceptible to this kind of treatment are transient in nature. For example, a remote call to a web service or an RMI service that fails because of a network glitch or a DeadLockLoserException in a database update may resolve itself after a short wait. To automate the retry of such operations, Spring Retry has the RetryOperations strategy.

为了使处理更加健壮,减少失败的可能性,有时候自动重试失败的操作。 目前有两个开源的类库 spring retry and guava retry 都支持编程式,spring retry 更加融合spring的aop 注解驱动,使用更加的方便。

模拟异常场景

为了实现demo,模拟了异常的场景

  • 异常调用
http://localhost:8080/unstableApi/500
  • 调用正常
http://localhost:8080/unstableApi/200
@RestController
public class MockApiController {

    /**
     * 模拟服务不正常
     *
     * @param status
     * @return
     */
    @GetMapping("/unstableApi/{status}")
    public ResponseEntity<Integer> unstableApi(@PathVariable int status) {
        if (INTERNAL_SERVER_ERROR.value() == status) {
            throw new ResponseStatusException(INTERNAL_SERVER_ERROR);
        }
        if (UNAUTHORIZED.value() == status) {
            throw new ResponseStatusException(UNAUTHORIZED);
        }
        return ResponseEntity.ok(status);
    }

}

实践

spring retry支持有状态和无状态两种方式。一般理解使用无状态。

  • 无状态: 无状态就是当前线程继续处理,spring retry 通过获取到异常后继续在当前线程重试。

  • 有状态: 类比http,http 调用是无状态的,为了增加访问状态可能增加cookie 标识一个人的访问,当前的多次访问是否是一个人; spring retry 中有状态我这么理解,多次调用不直接的在当前线程重试,将异常抛出,标识为【当前方法参数+方法名称】,记录下当前失败的key对应的记录。 下一次在继续调用对于相同的key可以进行失败统计,如果达到目标失败次数,会调用失败处理的兜底回调org.springframework.retry.RecoveryCallback 进行记录。 spring retry 中的 stateful 如何使用?

配置开关进行测试,要测试 将开关配置为true 即可观察日志!

#com.wangji92.retry.springretryexample.task.SchedulingTestRetryTask
#测试 retry的效果 是通过编程的方式 、还是通过 aop注解的方式测试

aopSpringRetry=true
programmingSpringRetry=false
programmingGuavaRetry=false

# 有状态的重试  com.wangji92.retry.springretryexample.task.SchedulingTestStateFullRetryTask
aopStateFullRetry=false
programmingStateFullRetry=false

所有的场景都是通过定时器进行调用模拟,具体使用可以参考链接

配置

spring retry

@EnableRetry(proxyTargetClass = true)

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
    <version>1.3.1</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

guava retry

<dependency>
    <groupId>com.github.rholder</groupId>
    <artifactId>guava-retrying</artifactId>
    <version>2.0.0</version>
</dependency>

withAttemptTimeLimiter 会导致执行业务的线程和调用线程非一个线程执行,会带来事务问题、线程上下文传递问题 还有一个问题 guava-retrying 对于最新版本的guava 没有支持 rholder/guava-retrying#66 使用的时候一定要小心啦,默认使用最新版本的guava,不推荐使用。

 // RetryerBuilder 构建重试实例 guavaRetryer,可以设置重试源且可以支持多个重试源,可以配置重试次数或重试超时时间,以及可以配置等待时间间隔
Retryer<Integer> guavaRetryer = RetryerBuilder.<Integer>newBuilder()
        //设置异常重试源 根据异常 也可以 retryIfResult 根据结果
        .retryIfExceptionOfType(RemoteAccessException.class)

        // 【这里将会使用多线程执行(other 线程执行、会导致事务问题、线程上下文传递问题 一定要小心)】 还有这个框架 这个属性高版本不支持了.
        .withAttemptTimeLimiter(new FixedAttemptTimeLimit<Integer>(1, TimeUnit.MINUTES))
        //设置等待间隔时间
        .withWaitStrategy(WaitStrategies.fixedWait(5, TimeUnit.SECONDS))
        //设置最大重试次数
        .withStopStrategy(StopStrategies.stopAfterAttempt(2))
        .build();

spring retry 框架的理解

spring retry 框架的理解 博客

参考文档