Retry

该功能抄录重构自 retry4j,主要为了学习其实现过程,支持以较为简单直观的方式执行重试。

类似的库还有:

1. 配置

RetryConfig<T> 的类型参数 T 为返回值的类型,在设置基于返回结果的重试策略时能够确保类型安全。

RetryConfig<String> config = Retry.<String>config()
    // 基于异常重试
    .retryOnError(IllegalArgumentException.class)
    .retryOnErrors(Arrays.asList(IndexOutOfBoundsException.class, IllegalStateException.class))
    .retryOnErrorMatch(e -> e.getMessage().contains("CODE"))
    .retryOnAnyErrorExclude(SQLException.class)
    .retryOnAnyError()
    
    // 匹配异常类型时使用根源异常类型
    .retryOnErrorOfCausedBy()
    
    // 出现任意异常直接失败
    .failOnAnyError()
    
    // 基于返回结果重试
    .retryOnValue("ILLEGAL_VALUE")
    .retryOnValues("ILLEGAL_VALUE_1", "ILLEGAL_VALUE_2")
    .retryOnAnyValueExclude("LEGAL_VALUE_3")
    .retryOnValueMatch(v -> v.startsWith("LEGAL"))
    
    // 重试次数或无限重试
    .withMaxAttempts(2)
    .withInfiniteAttempts()
    
    // 重试之间的延迟间隔
    .withDelayDuration(Duration.ofSeconds(3))
    
    // 重试时的回退策略
    .withFixedBackoff()
    .withExponentialBackoff()
    .withFibonacciBackoff()
    .withNoDelayBackoff()
    .withRandomBackoff()
    .withRandomExponentialBackoff()
    .withCustomBackoff(new BackoffStrategy() {
        @Override
        public Duration nextDelayToWait(int failedAttempts, Duration delayDuration) {
            return null;
        }

        @Override
        public Duration nextDelayToWait(int failedAttempts, Duration delayDuration, Object lastValue, Exception lastError) {
            // 基于当前重试次数、结果、异常,返回下次重试的延迟间隔
            return Duration.seconds(10);
        }
    })
    
    // 监听不同重试时机的状态
    .listenSuccedTry(System.out::println)
    .listenFailedTry(System.out::println)
    .listenCompleteTry(System.out::println)
    .listenBeforeNextTry(System.out::println)
    .listenAfterFailTry(System.out::println)
    
    // 设置异步重试时使用的线程池
    .asyncThreadPool(Executors.newFixedThreadPool(6))
    
    .build();
    
// 或者直接使用预定义好的常见策略
Retry.<String>config().fixedBackoff2Tries3Sec();
Retry.<String>config().fixedBackoff5Tries10Sec();
Retry.<String>config().exponentialBackoff5Tries5Sec();
Retry.<String>config().fiboBackoff7Tries5Sec();
Retry.<String>config().randomExpBackoff10Tries60Sec();

2. 执行

// 同步重试,将会阻塞当前执行线程
RetryStatus<String> syncStatus = Retry.runSync(config, () -> "result");

// 异步重试,创建新线程或使用提供的线程池
CompletableFuture<RetryStatus<String>> asyncStatus = Retry.runAsync(config, () -> "result");