resilience4j 공식 레퍼런스를 한글로 번역한 문서입니다.
전체 목차는 여기에 있습니다.
목차
- Create a RetryRegistry
- Create and configure Retry
- Decorate and execute a functional interface
- Consume emitted RegistryEvents
- Use a custom IntervalFunction
Create a RetryRegistry
이 모듈은 CircuitBreaker 모듈과 동일하게 Retry 인스턴스들을 관리(생성/조회)할 수 있는 인 메모리 RetryRegistry
를 제공한다.
RetryRegistry retryRegistry = RetryRegistry.ofDefaults();
Create and configure Retry
커스텀 글로벌 RetryConfig
를 제공하는 것도 가능하다. 커스텀 글로벌 RetryConfig
를 생성할 땐 RetryConfig 빌더를 사용하면 된다. 이 빌더를 통해 다음과 같은 프로퍼티를 설정할 수 있다:
- 최대 시도 횟수
- 연이어서 시도할때 기다릴 시간
- 실패했을 때 대기할 시간을 시도 횟수와 결과/예외를 가지고 계산하는 커스텀 IntervalBiFunction
- 특정 응답이 재시도를 트리거해야 하는지를 평가하는 커스텀 Predicate
- 예외가 재시도를 트리거해야 하는지를 평가하는 커스텀 Predicate
- 재시도를 트리거할 예외 목록
- 무시하고 재시도를 트리거하지 않을 예외 목록
Config property | Default value | Description |
---|---|---|
maxAttempts | 3 | 최대로 시도해볼 횟수 (최초 호출도 포함) |
waitDuration | 500 [ms] | 재시도할 때마다 기다리는 고정 시간 |
intervalFunction | numOfAttempts -> waitDuration | 실패했을 때 대기할 시간을 수정하는 함수. 기본적으로는 대기 시간을 일정하게 유지한다. |
intervalBiFunction | (numOfAttempts, Either<throwable, result) -> waitDuration | 실패했을 때 대기할 시간을 시도 횟수와 결과/예외에 따라 수정하는 함수. intervalFunction 과 함께 사용하면 IllegalStateException이 발생한다. |
retryOnResultPredicate | result -> false | 결과를 보고 재시도해야 할지 평가하는 Predicate. 재시도해야 한다면 true를, 그 외엔 false를 반환해야 한다. |
retryOnExceptionPredicate | throwable -> true | 예외를 보고 재시도해야 할지 평가하는 Predicate. 재시도해야 한다면 true를, 그 외엔 false를 반환해야 한다. |
retryExceptions | empty | 실패로 기록해서 재시도할 Throwable 클래스 목록. 하위 타입을 지원한다. 참고: Checked Exception을 사용하려면 CheckedSupplier를 사용해야 한다. |
ignoreExceptions | empty | 무시하고 재시도하지 않을 Throwable 클래스 목록. 하위 타입을 지원한다. |
failAfterMaxAttempts | false | 설정한 maxAttempts 만큼 재시도하고 나서도 결과가 여전히 retryOnResultPredicate 를 통과하지 못했을 때 MaxRetriesExceededException 발생을 활성화/비활성화하는 boolean |
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도 CircuitBreaker에 있던 고차원 데코레이터 함수를 모두 가지고 있다. Callable
, Supplier
, Runnable
, Consumer
, CheckedRunnable
, CheckedSupplier
, CheckedConsumer
, CompletionStage
라면 모두 Retry로 데코레이트할 수 있다.
// 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가 생성, 교체, 삭제될 때마다 필요한 로직을 실행할 수 있다.
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 a custom IntervalFunction
재시도할 때마다 같은 시간을 기다리고 싶지 않다면 IntervalFunction
을 설정하면 된다. 이렇게 하면 매시도마다 대기 시간을 새로 계산한다. Resilience4j는 간단히 IntervalFunction
을 만들 수 있는 몇 가지 팩토리 메소드를 제공한다.
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();
Next :Retry Examples
Retry 사용 예시 한글 번역
전체 목차는 여기에 있습니다.