doc: 阅读Retry文档

This commit is contained in:
asahi
2025-09-03 15:34:48 +08:00
parent 7f060618a9
commit 4ddad7d316

View File

@@ -32,6 +32,12 @@
- [decorate and execute a functional interface](#decorate-and-execute-a-functional-interface-2) - [decorate and execute a functional interface](#decorate-and-execute-a-functional-interface-2)
- [consume emitted RegistryEvents](#consume-emitted-registryevents-2) - [consume emitted RegistryEvents](#consume-emitted-registryevents-2)
- [consume emitted RateLimiterEvents](#consume-emitted-ratelimiterevents) - [consume emitted RateLimiterEvents](#consume-emitted-ratelimiterevents)
- [Retry](#retry)
- [Create a RetryRegistry](#create-a-retryregistry)
- [Create and configure Retry](#create-and-configure-retry)
- [Decorate and execute a functional interface](#decorate-and-execute-a-functional-interface-3)
- [consume emitted RegistryEvents](#consume-emitted-registryevents-3)
- [use custom IntervalFunction](#use-custom-intervalfunction)
# CircuitBreaker # CircuitBreaker
@@ -704,3 +710,155 @@ ReactorAdapter.toFlux(rateLimiter.getEventPublisher())
.filter(event -> event.getEventType() == FAILED_ACQUIRE) .filter(event -> event.getEventType() == FAILED_ACQUIRE)
.subscribe(event -> logger.info(...)) .subscribe(event -> logger.info(...))
``` ```
## Retry
### Create a RetryRegistry
和CircuitBreaker module类似该module也提供了in-memory RetryRegistry用于对Retry对象进行管理。
```java
RetryRegistry retryRegistry = RetryRegistry.ofDefaults();
```
### Create and configure Retry
可以提供一个自定义的global RetryConfig可以使用builder来创建RetryConfig。
RetryConfig支持如下配置
- `maxAttempts`:
- `default value`: 3
- `description`该参数代表最大尝试次数包含最初始的调用最初始的调用为first attemp
- `waitDuration`:
- `default value`: 500 [ms]
- `description`: 在多次retry attempts之间的固定等待间隔
- `intervalFunction`:
- `defaultValue`: `numOfAttempts -> waitDuration`
- `description`: 该参数对应的function用于在失败后修改等待时间默认情况下每次失败后等待时间是固定的都是waitDuration
- `intervalBiFunction`:
- `default value`: `(int numOfAttempts, Either<Throwable, T> result)->waitDuration`
- `description`: 该function用于在failure后修改等待时间间隔即基于attempt number和result/exception来计算等待时间间隔。当同时使用`intervalFunction``intervalBiFunction`时,会抛出异常
- `retryOnResultPredicate`
- `default value`: `result -> false`
- `description`: 该参数用于配置predicate用于判断result是否应该被重试。如果result应当被重试那么返回true否则返回false
- `retryOnExceptionPredicate`:
- `default`: `throwable -> true`
- `description`: 该参数用于判断是否exception应当被重试。如果exception应当被重试predicate返回true否则返回false
- `retryExceptions`
- `default value`: empty
- `description`: 配置exception list其将被记录为failure并且应当被重试。
- `ignoreExceptions`:
- `default value`: empty
- `descritpion`: 配置exception list该列表中的异常会被ignore并且不会重试
- `failAfterMaxAttempts`:
- `default value`: false
- `description`: 该参数用于启用和关闭`MaxRetriesExceededException`的抛出当Retry达到配置的maxAttempts后若result没有通过`retryOnResultPredicate`,则会根据`failAfterMaxAttempts`来重试
> 在抛出异常后,是否重试的逻辑如下:
> - 根据predicate判断该异常是否应该重试predicate逻辑判断流程如下
> - 如果异常位于ignoreExceptions中则不应重试
> - 如果异常位于retryExceptions中则predicate返回为true
> - 如果异常不位于retryExceptions中则根据retryOnExceptionPredicate来判断是否异常应当触发重试
> - 如果上述的predicate判断异常应该被重试那么再递增重试次数判断当前重试是否超过maxAttempts
> - 如果没有超过则在等待interval后触发重试
> - 如果超过maxAttempts规定的上限则不再重试直接抛出异常
> 在未抛出异常时,判断是否重试的逻辑如下:
> - 首先,根据`retryOnResultPredicate`判断当前返回结果是否应当触发重试,如果不应触发重试,则流程结束
> - 如果应当触发重试则增加当前的重试次数并和maxAttempts进行比较
> - 如果当前重试次数未超过maxAttempts则在等待interval后触发重试
> - 如果重试次数超过maxAttempts规定的值那么将根据failAfterMaxAttempts来决定是否抛出异常。当failAfterMaxAttempts为true时抛出异常当为false时不跑出异常。默认不会抛出异常。
创建RetryConfig的默认示例如下
```java
RetryConfig config = RetryConfig.custom()
.maxAttempts(2)
.waitDuration(Duration.ofMillis(1000))
.retryOnResult(response -> response.getStatus() == 500)
.retryOnException(e -> e instanceof WebServiceException)
.retryExceptions(IOException.class, TimeoutException.class)
.ignoreExceptions(BusinessException.class, OtherBusinessException.class)
.failAfterMaxAttempts(true)
.build();
// Create a RetryRegistry with a custom global configuration
RetryRegistry registry = RetryRegistry.of(config);
// Get or create a Retry from the registry -
// Retry will be backed by the default config
Retry retryWithDefaultConfig = registry.retry("name1");
// Get or create a Retry from the registry,
// use a custom configuration when creating the retry
RetryConfig custom = RetryConfig.custom()
.waitDuration(Duration.ofMillis(100))
.build();
Retry retryWithCustomConfig = registry.retry("name2", custom);
```
### Decorate and execute a functional interface
Retry可以针对`callable, supplier, runnable, consumer, checkedrunnable, checkedsupplier, checkedconsumer, completionstage`进行decorate使用示例如下
```java
// Given I have a HelloWorldService which throws an exception
HelloWorldService helloWorldService = mock(HelloWorldService.class);
given(helloWorldService.sayHelloWorld())
.willThrow(new WebServiceException("BAM!"));
// Create a Retry with default configuration
Retry retry = Retry.ofDefaults("id");
// Decorate the invocation of the HelloWorldService
CheckedFunction0<String> retryableSupplier = Retry
.decorateCheckedSupplier(retry, helloWorldService::sayHelloWorld);
// When I invoke the function
Try<String> result = Try.of(retryableSupplier)
.recover((throwable) -> "Hello world from recovery function");
// Then the helloWorldService should be invoked 3 times
BDDMockito.then(helloWorldService).should(times(3)).sayHelloWorld();
// and the exception should be handled by the recovery function
assertThat(result.get()).isEqualTo("Hello world from recovery function");
```
### consume emitted RegistryEvents
可以向RetryRegistry注册监听消费Retry的create, replace, delete事件
```java
RetryRegistry registry = RetryRegistry.ofDefaults();
registry.getEventPublisher()
.onEntryAdded(entryAddedEvent -> {
Retry addedRetry = entryAddedEvent.getAddedEntry();
LOG.info("Retry {} added", addedRetry.getName());
})
.onEntryRemoved(entryRemovedEvent -> {
Retry removedRetry = entryRemovedEvent.getRemovedEntry();
LOG.info("Retry {} removed", removedRetry.getName());
});
```
### use custom IntervalFunction
如果不想使用fixed wait duration可以自定义`IntervalFunction`该函数可以在每次attempt时独立计算wait duration。resilience4j支持一些工厂方法用于创建IntervalFunction示例如下
```java
IntervalFunction defaultWaitInterval = IntervalFunction
.ofDefaults();
// This interval function is used internally
// when you only configure waitDuration
IntervalFunction fixedWaitInterval = IntervalFunction
.of(Duration.ofSeconds(5));
IntervalFunction intervalWithExponentialBackoff = IntervalFunction
.ofExponentialBackoff();
IntervalFunction intervalWithCustomExponentialBackoff = IntervalFunction
.ofExponentialBackoff(IntervalFunction.DEFAULT_INITIAL_INTERVAL, 2d);
IntervalFunction randomWaitInterval = IntervalFunction
.ofRandomized();
// Overwrite the default intervalFunction with your custom one
RetryConfig retryConfig = RetryConfig.custom()
.intervalFunction(intervalWithExponentialBackoff)
.build();
```
> intervalFunction和intervalBiFunction不能同时指定同时指定时会抛出异常。
>
> 如果指定了intervalFunction那么在通过builder创建RetryConfig时会自动通过intervalFunction给intervalBiFunction也赋值。
>
> 如果指定了intervalFunction或intervalBiFunction中任一则使用指定的函数来计算waitDuration当二者都没有指定时则waitDuration固定为waitDuration