RetryOperator implements UnaryOperator<Publisher<T>> { public static <T> RetryOperator<T> of(Retry retry) { return new RetryOperator<>(retry); } private  RetryOperator(Retry retry); static RetryOperator<T> of(Retry retry); @Override Publisher<T> apply(Publisher<T> publisher);  }
@Test public void returnOnCompleteUsingMono() { RetryConfig config = retryConfig(); Retry retry = Retry.of("testName", config); RetryOperator<String> retryOperator = RetryOperator.of(retry); given(helloWorldService.returnHelloWorld()) .willReturn("Hello world") .willThrow(new HelloWorldException()) .willThrow(new HelloWorldException()) .willReturn("Hello world"); StepVerifier.create(Mono.fromCallable(helloWorldService::returnHelloWorld) .transformDeferred(retryOperator)) .expectNext("Hello world") .expectComplete() .verify(Duration.ofSeconds(1)); StepVerifier.create(Mono.fromCallable(helloWorldService::returnHelloWorld) .transformDeferred(retryOperator)) .expectNext("Hello world") .expectComplete() .verify(Duration.ofSeconds(1)); then(helloWorldService).should(times(4)).returnHelloWorld(); Retry.Metrics metrics = retry.getMetrics(); assertThat(metrics.getNumberOfSuccessfulCallsWithoutRetryAttempt()).isEqualTo(1); assertThat(metrics.getNumberOfSuccessfulCallsWithRetryAttempt()).isEqualTo(1); assertThat(metrics.getNumberOfFailedCallsWithRetryAttempt()).isEqualTo(0); assertThat(metrics.getNumberOfFailedCallsWithoutRetryAttempt()).isEqualTo(0); }
@Test(expected = StackOverflowError.class) public void shouldNotRetryUsingMonoStackOverFlow() { RetryConfig config = retryConfig(); Retry retry = Retry.of("testName", config); RetryOperator<String> retryOperator = RetryOperator.of(retry); given(helloWorldService.returnHelloWorld()) .willThrow(new StackOverflowError("BAM!")); StepVerifier.create(Mono.fromCallable(helloWorldService::returnHelloWorld) .transformDeferred(retryOperator)) .expectSubscription() .expectError(StackOverflowError.class) .verify(Duration.ofSeconds(1)); }
@Test public void shouldNotRetryWhenItThrowErrorMono() { RetryConfig config = retryConfig(); Retry retry = Retry.of("testName", config); RetryOperator<String> retryOperator = RetryOperator.of(retry); given(helloWorldService.returnHelloWorld()) .willThrow(new Error("BAM!")); StepVerifier.create(Mono.fromCallable(helloWorldService::returnHelloWorld) .transformDeferred(retryOperator)) .expectSubscription() .expectError(Error.class) .verify(Duration.ofSeconds(1)); then(helloWorldService).should().returnHelloWorld(); Retry.Metrics metrics = retry.getMetrics(); assertThat(metrics.getNumberOfFailedCallsWithRetryAttempt()).isEqualTo(0); assertThat(metrics.getNumberOfFailedCallsWithoutRetryAttempt()).isEqualTo(0); }
@Test public void returnOnErrorUsingMono() { RetryConfig config = retryConfig(); Retry retry = Retry.of("testName", config); RetryOperator<String> retryOperator = RetryOperator.of(retry); given(helloWorldService.returnHelloWorld()) .willThrow(new HelloWorldException()); StepVerifier.create(Mono.fromCallable(helloWorldService::returnHelloWorld) .transformDeferred(retryOperator)) .expectSubscription() .expectError(HelloWorldException.class) .verify(Duration.ofSeconds(1)); StepVerifier.create(Mono.fromCallable(helloWorldService::returnHelloWorld) .transformDeferred(retryOperator)) .expectSubscription() .expectError(HelloWorldException.class) .verify(Duration.ofSeconds(1)); then(helloWorldService).should(times(6)).returnHelloWorld(); Retry.Metrics metrics = retry.getMetrics(); assertThat(metrics.getNumberOfFailedCallsWithRetryAttempt()).isEqualTo(2); assertThat(metrics.getNumberOfFailedCallsWithoutRetryAttempt()).isEqualTo(0); }
@Test public void doNotRetryFromPredicateUsingMono() { RetryConfig config = RetryConfig.custom() .retryOnException(t -> t instanceof IOException) .waitDuration(Duration.ofMillis(50)) .maxAttempts(3).build(); Retry retry = Retry.of("testName", config); given(helloWorldService.returnHelloWorld()) .willThrow(new HelloWorldException()); StepVerifier.create(Mono.fromCallable(helloWorldService::returnHelloWorld) .transformDeferred(RetryOperator.of(retry))) .expectSubscription() .expectError(HelloWorldException.class) .verify(Duration.ofSeconds(1)); then(helloWorldService).should().returnHelloWorld(); Retry.Metrics metrics = retry.getMetrics(); assertThat(metrics.getNumberOfFailedCallsWithoutRetryAttempt()).isEqualTo(1); assertThat(metrics.getNumberOfFailedCallsWithRetryAttempt()).isEqualTo(0); }
@Test public void retryOnResultUsingMono() { RetryConfig config = RetryConfig.<String>custom() .retryOnResult("retry"::equals) .waitDuration(Duration.ofMillis(10)) .maxAttempts(3).build(); Retry retry = Retry.of("testName", config); given(helloWorldService.returnHelloWorld()) .willReturn("retry") .willReturn("success"); StepVerifier.create(Mono.fromCallable(helloWorldService::returnHelloWorld) .transformDeferred(RetryOperator.of(retry))) .expectSubscription() .expectNext("success") .expectComplete() .verify(Duration.ofSeconds(1)); then(helloWorldService).should(times(2)).returnHelloWorld(); Retry.Metrics metrics = retry.getMetrics(); assertThat(metrics.getNumberOfFailedCallsWithoutRetryAttempt()).isEqualTo(0); assertThat(metrics.getNumberOfSuccessfulCallsWithRetryAttempt()).isEqualTo(1); }
@Test public void retryOnResultFailAfterMaxAttemptsUsingMono() { RetryConfig config = RetryConfig.<String>custom() .retryOnResult("retry"::equals) .waitDuration(Duration.ofMillis(10)) .maxAttempts(3).build(); Retry retry = Retry.of("testName", config); given(helloWorldService.returnHelloWorld()) .willReturn("retry"); StepVerifier.create(Mono.fromCallable(helloWorldService::returnHelloWorld) .transformDeferred(RetryOperator.of(retry))) .expectSubscription() .expectNextCount(1) .expectComplete() .verify(Duration.ofSeconds(1)); then(helloWorldService).should(times(3)).returnHelloWorld(); }
@Test public void shouldFailWithExceptionFlux() { RetryConfig config = retryConfig(); Retry retry = Retry.of("testName", config); RetryOperator<Object> retryOperator = RetryOperator.of(retry); StepVerifier.create(Flux.error(new HelloWorldException()) .transformDeferred(retryOperator)) .expectSubscription() .expectError(HelloWorldException.class) .verify(Duration.ofSeconds(1)); Retry.Metrics metrics = retry.getMetrics(); assertThat(metrics.getNumberOfSuccessfulCallsWithoutRetryAttempt()).isEqualTo(0); assertThat(metrics.getNumberOfSuccessfulCallsWithRetryAttempt()).isEqualTo(0); assertThat(metrics.getNumberOfFailedCallsWithRetryAttempt()).isEqualTo(1); assertThat(metrics.getNumberOfFailedCallsWithoutRetryAttempt()).isEqualTo(0); }
@Test public void retryOnResultUsingFlux() { RetryConfig config = RetryConfig.<String>custom() .retryOnResult("retry"::equals) .waitDuration(Duration.ofMillis(10)) .maxAttempts(3).build(); Retry retry = Retry.of("testName", config); StepVerifier.create(Flux.just("retry", "success") .transformDeferred(RetryOperator.of(retry))) .expectSubscription() .expectNext("retry") .expectNext("success") .expectComplete() .verify(Duration.ofMillis(100)); Retry.Metrics metrics = retry.getMetrics(); assertThat(metrics.getNumberOfFailedCallsWithoutRetryAttempt()).isEqualTo(0); assertThat(metrics.getNumberOfFailedCallsWithRetryAttempt()).isEqualTo(1); }
@Test public void retryOnResultFailAfterMaxAttemptsUsingFlux() { RetryConfig config = RetryConfig.<String>custom() .retryOnResult("retry"::equals) .waitDuration(Duration.ofMillis(10)) .maxAttempts(3).build(); Retry retry = Retry.of("testName", config); StepVerifier.create(Flux.just("retry") .transformDeferred(RetryOperator.of(retry))) .expectSubscription() .expectNextCount(1) .expectComplete() .verify(Duration.ofSeconds(1)); Retry.Metrics metrics = retry.getMetrics(); assertThat(metrics.getNumberOfFailedCallsWithoutRetryAttempt()).isEqualTo(0); assertThat(metrics.getNumberOfFailedCallsWithRetryAttempt()).isEqualTo(1); }