static IntervalFunction ofDefaults() { return of(DEFAULT_INITIAL_INTERVAL); }
static IntervalFunction of(Duration interval, Function<Long, Long> backoffFunction) { return of(interval.toMillis(), backoffFunction); }
static IntervalFunction of(Duration interval) { return of(interval.toMillis()); }
static IntervalFunction ofExponentialBackoff(long initialIntervalMillis, double multiplier) { checkMultiplier(multiplier); return of(initialIntervalMillis, (x) -> (long) (x * multiplier)); }
@Test public void shouldRejectNonPositiveDuration() { // Given final Duration negativeDuration = Duration.ofMillis(0); final Duration zeroDuration = Duration.ofMillis(0); final Duration smallDuration = Duration.ofMillis(9); final long negativeInterval = -1; final long zeroInterval = 0; final long smallInterval = 9; // When List<Try> tries = List.of( Try.of(() -> IntervalFunction.of(negativeDuration)), Try.of(() -> IntervalFunction.of(zeroDuration)), Try.of(() -> IntervalFunction.of(smallDuration)), Try.of(() -> IntervalFunction.of(negativeInterval)), Try.of(() -> IntervalFunction.of(zeroInterval)), Try.of(() -> IntervalFunction.of(smallInterval)) ); // Then Assertions.assertThat(tries.forAll(Try::isFailure)).isTrue(); Assertions.assertThat(tries.map(Try::getCause).forAll(t -> t instanceof IllegalArgumentException)).isTrue(); }
static IntervalFunction ofExponentialRandomBackoff( long initialIntervalMillis, double multiplier, double randomizationFactor ) { checkInterval(initialIntervalMillis); checkMultiplier(multiplier); checkRandomizationFactor(randomizationFactor); return (attempt) -> { checkAttempt(attempt); final long interval = of(initialIntervalMillis, (x) -> (long) (x * multiplier)).apply(attempt); return (long) randomize(interval, randomizationFactor); }; }
@Test public void shouldTakeIntoAccountBackoffFunction() { // Given the HelloWorldService throws an exception BDDMockito.willThrow(new WebServiceException("BAM!")).given(helloWorldService).sayHelloWorld(); // Create a Retry with a backoff function squaring the interval RetryConfig config = RetryConfig .custom() .intervalFunction(IntervalFunction.of(Duration.ofMillis(500), x -> x * x)) .build(); Retry retry = Retry.of("id", config); // Decorate the invocation of the HelloWorldService CheckedRunnable retryableRunnable = Retry.decorateCheckedRunnable(retry, helloWorldService::sayHelloWorld); // When Try<Void> result = Try.run(retryableRunnable); // Then the slept time should be according to the backoff function BDDMockito.then(helloWorldService).should(Mockito.times(3)).sayHelloWorld(); Assertions.assertThat(sleptTime).isEqualTo( RetryConfig.DEFAULT_WAIT_DURATION + RetryConfig.DEFAULT_WAIT_DURATION*RetryConfig.DEFAULT_WAIT_DURATION); } }