使用resilience4j-retry实现函数调用重试

18-12-08 banq
              

Resilience4j中有一个特殊模块(Resilience4j -Retry),它是为Java8和函数式编程设计的容错库,它是具有最小依赖性的轻量级库(主要是vavr) 

当你重试时,有很多例子:

  • 用于远程系统调用的跨微服务通信,其中很可能还需要添加断路器逻辑
  • 如果您有业务或功能逻辑需要获得一致的结束状态,并且很可能是异步流

好的,你需要做什么才能开始使用resileience4j重试:

如果你使用maven:

<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-retry</artifactId>
    <version>0.13.2</version>
</dependency>
<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-core</artifactId>
    <version>0.13.2</version>
</dependency>

重试模块可以有以下功能:

  • 同步重试和异步重试
  • 关于异常或响应谓词的Rety,如果您想要重试特定的响应值而不仅仅是抛出异常,这可能很有用
  • 重试配置的退避策略加上最大重试次数
  • 忽略不重试的异常集
  • 它支持checked(添加了异常处理)和未检查的函数执行(ex Function,Supplier,Callable,Runnable ..)
  • 如果需要,它可以与spring集成。

如何配置异步重试,在Github上测试resilience4j重试的完整代码:

// Given the HelloWorldService returns Hello world
given(helloWorldService.returnHelloWorld())
    .willReturn(completedFuture("Hello world"));

final AsyncRetry retryContext = AsyncRetry.of("retryConfig",
        // we set the response type to String
        RetryConfig.<String>custom()
                // max retry attempts
                .maxAttempts(3)
                // what are the ignore exception to no retry on
                .ignoreExceptions(IllegalStateException.class)
                // what are the exceptions to try on
                .retryExceptions(TimeoutException.class)
                // retry if the response contains world
                .retryOnResult(s -> s.contains("world"))
                // retry backoff strategy, IntervalFunction has many built in interface functions you can check it out
                .intervalFunction(IntervalFunction.ofExponentialBackoff())
                .build());

// Decorate the invocation of the HelloWorldService
Supplier<CompletionStage<String>> supplier = AsyncRetry.decorateCompletionStage(
            retryContext,
            scheduler,
            () -> helloWorldService.returnHelloWorld());

// When
String result = awaitResult(supplier);
// Then the helloWorldService should be invoked 1 time
BDDMockito.then(helloWorldService).should(Mockito.times(3)).returnHelloWorld();
Assertions.assertEquals(result, "Hello world");

对于同步调用,您有许多选项(Supplier , Callable , Function 。。)

// Given the HelloWorldService returns Hello world
BDDMockito.given(helloWorldService.returnHelloWorld()).willReturn("Hello world");
// Create a Retry with default configuration
final RetryConfig tryAgain = RetryConfig.<String>custom().retryOnResult(s -> s.contains("Hello world"))
                .maxAttempts(2).build();
Retry retry = Retry.of("id", tryAgain);
// Decorate the invocation of the HelloWorldService
Supplier<String> supplier = Retry.decorateSupplier(retry, helloWorldService::returnHelloWorld);
// When
String result = supplier.get();
// Then the helloWorldService should be invoked 1 time
BDDMockito.then(helloWorldService).should(Mockito.times(2)).returnHelloWorld();
assertThat(result).isEqualTo("Hello world");