Skip to content

Commit

Permalink
Introduce java.time.Duration
Browse files Browse the repository at this point in the history
  • Loading branch information
aahlenst committed May 25, 2023
1 parent 95464af commit ff0588e
Show file tree
Hide file tree
Showing 2 changed files with 173 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package org.springframework.retry.support;

import java.time.Duration;
import java.util.ArrayList;
import java.util.List;

Expand Down Expand Up @@ -132,6 +133,20 @@ public RetryTemplateBuilder withinMillis(long timeout) {
return this;
}

/**
* Retry until {@code timeout} has passed since the initial attempt.
* @param timeout duration for how long retries should be attempted
* @return this
* @see TimeoutRetryPolicy
* @throws IllegalArgumentException if timeout is {@code null} or 0, or if another
* retry policy has already been configured.
* @since 2.0.2
*/
public RetryTemplateBuilder withTimeout(Duration timeout) {
Assert.notNull(timeout, "timeout is null");
return this.withinMillis(timeout.toMillis());
}

/**
* Allows infinite retry, do not limit attempts by number or time.
* <p>
Expand Down Expand Up @@ -180,6 +195,27 @@ public RetryTemplateBuilder exponentialBackoff(long initialInterval, double mult
return exponentialBackoff(initialInterval, multiplier, maxInterval, false);
}

/**
* Use exponential backoff policy. The formula of backoff period:
* <p>
* {@code currentInterval = Math.min(initialInterval * Math.pow(multiplier, retryNum), maxInterval)}
* <p>
* (for first attempt retryNum = 0)
* @param initialInterval initial sleep duration
* @param multiplier backoff interval multiplier
* @param maxInterval maximum backoff duration
* @return this
* @see ExponentialBackOffPolicy
* @throws IllegalArgumentException if initialInterval is {@code null}, multiplier is
* <= 1 or if maxInterval is {@code null}
* @since 2.0.2
*/
public RetryTemplateBuilder exponentialBackoff(Duration initialInterval, double multiplier, Duration maxInterval) {
Assert.notNull(initialInterval, "initialInterval is null");
Assert.notNull(maxInterval, "maxInterval is null");
return exponentialBackoff(initialInterval.toMillis(), multiplier, maxInterval.toMillis(), false);
}

/**
* Use exponential backoff policy. The formula of backoff period (without randomness):
* <p>
Expand Down Expand Up @@ -210,6 +246,31 @@ public RetryTemplateBuilder exponentialBackoff(long initialInterval, double mult
return this;
}

/**
* Use exponential backoff policy. The formula of backoff period (without randomness):
* <p>
* {@code currentInterval = Math.min(initialInterval * Math.pow(multiplier, retryNum), maxInterval)}
* <p>
* (for first attempt retryNum = 0)
* @param initialInterval initial sleep duration
* @param multiplier backoff interval multiplier
* @param maxInterval maximum backoff duration
* @param withRandom adds some randomness to backoff intervals. For details, see
* {@link ExponentialRandomBackOffPolicy}
* @return this
* @see ExponentialBackOffPolicy
* @see ExponentialRandomBackOffPolicy
* @throws IllegalArgumentException if initialInterval is {@code null}, multiplier is
* <= 1 or maxInterval is {@code null}
* @since 2.0.2
*/
public RetryTemplateBuilder exponentialBackoff(Duration initialInterval, double multiplier, Duration maxInterval,
boolean withRandom) {
Assert.notNull(initialInterval, "initialInterval is null");
Assert.notNull(maxInterval, "maxInterval is null");
return this.exponentialBackoff(initialInterval.toMillis(), multiplier, maxInterval.toMillis(), withRandom);
}

/**
* Perform each retry after fixed amount of time.
* @param interval fixed interval in milliseconds
Expand All @@ -225,6 +286,24 @@ public RetryTemplateBuilder fixedBackoff(long interval) {
return this;
}

/**
* Perform each retry after fixed amount of time.
* @param interval fixed backoff duration
* @return this
* @see FixedBackOffPolicy
* @throws IllegalArgumentException if another backoff policy has already been
* configured, interval is {@code null} or less than 1 millisecond
* @since 2.0.2
*/
public RetryTemplateBuilder fixedBackoff(Duration interval) {
Assert.notNull(interval, "interval is null");

long millis = interval.toMillis();
Assert.isTrue(millis >= 1, "interval is less than 1 millisecond");

return this.fixedBackoff(millis);
}

/**
* Use {@link UniformRandomBackOffPolicy}, see it's doc for details.
* @param minInterval in milliseconds
Expand All @@ -244,6 +323,23 @@ public RetryTemplateBuilder uniformRandomBackoff(long minInterval, long maxInter
return this;
}

/**
* Use {@link UniformRandomBackOffPolicy}.
* @param minInterval minimum backoff duration
* @param maxInterval maximum backoff duration
* @return this
* @see UniformRandomBackOffPolicy
* @throws IllegalArgumentException if minInterval is {@code null} or < 1, maxInterval
* is {@code null} or < 1, maxInterval >= minInterval or if another backoff policy has
* already been configured.
* @since 2.0.2
*/
public RetryTemplateBuilder uniformRandomBackoff(Duration minInterval, Duration maxInterval) {
Assert.notNull(minInterval, "minInterval is null");
Assert.notNull(maxInterval, "maxInterval is null");
return this.uniformRandomBackoff(minInterval.toMillis(), maxInterval.toMillis());
}

/**
* Do not pause between attempts, retry immediately.
* @return this
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import java.io.FileNotFoundException;
import java.io.IOException;
import java.time.Duration;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
Expand All @@ -29,6 +30,7 @@
import org.springframework.retry.RetryPolicy;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
import org.springframework.retry.backoff.ExponentialRandomBackOffPolicy;
import org.springframework.retry.backoff.FixedBackOffPolicy;
import org.springframework.retry.backoff.NoBackOffPolicy;
import org.springframework.retry.backoff.UniformRandomBackOffPolicy;
import org.springframework.retry.policy.AlwaysRetryPolicy;
Expand Down Expand Up @@ -122,6 +124,17 @@ public void testTimeoutPolicy() {
assertThat(((TimeoutRetryPolicy) policyTuple.baseRetryPolicy).getTimeout()).isEqualTo(10000);
}

@Test
public void testTimeoutDuration() {
RetryTemplate template = RetryTemplate.builder().withTimeout(Duration.ofSeconds(3)).build();

PolicyTuple policyTuple = PolicyTuple.extractWithAsserts(template);
assertDefaultClassifier(policyTuple);

assertThat(policyTuple.baseRetryPolicy).isInstanceOf(TimeoutRetryPolicy.class);
assertThat(((TimeoutRetryPolicy) policyTuple.baseRetryPolicy).getTimeout()).isEqualTo(3000);
}

@Test
public void testInfiniteRetry() {
RetryTemplate template = RetryTemplate.builder().infiniteRetry().build();
Expand Down Expand Up @@ -185,24 +198,88 @@ public void testFailOnBackOffPolicyConflict() {
.isThrownBy(() -> RetryTemplate.builder().noBackoff().fixedBackoff(1000).build());
}

@Test
public void testFixedBackoff() {
RetryTemplate template = RetryTemplate.builder().fixedBackoff(200).build();
FixedBackOffPolicy policy = getPropertyValue(template, "backOffPolicy", FixedBackOffPolicy.class);

assertThat(policy.getBackOffPeriod()).isEqualTo(200);
}

@Test
public void testFixedBackoffDuration() {
RetryTemplate template = RetryTemplate.builder().fixedBackoff(Duration.ofSeconds(1)).build();
FixedBackOffPolicy policy = getPropertyValue(template, "backOffPolicy", FixedBackOffPolicy.class);

assertThat(policy.getBackOffPeriod()).isEqualTo(1000);
}

@Test
public void testUniformRandomBackOff() {
RetryTemplate template = RetryTemplate.builder().uniformRandomBackoff(10, 100).build();
assertThat(getPropertyValue(template, "backOffPolicy")).isInstanceOf(UniformRandomBackOffPolicy.class);
}

@Test
public void testUniformRandomBackOffDuration() {
RetryTemplate template = RetryTemplate.builder()
.uniformRandomBackoff(Duration.ofSeconds(1), Duration.ofSeconds(2)).build();

UniformRandomBackOffPolicy policy = getPropertyValue(template, "backOffPolicy",
UniformRandomBackOffPolicy.class);

assertThat(policy.getMinBackOffPeriod()).isEqualTo(1000);
assertThat(policy.getMaxBackOffPeriod()).isEqualTo(2000);
}

@Test
public void testNoBackOff() {
RetryTemplate template = RetryTemplate.builder().noBackoff().build();
assertThat(getPropertyValue(template, "backOffPolicy")).isInstanceOf(NoBackOffPolicy.class);
}

@Test
public void testExponentialBackoff() {
RetryTemplate template = RetryTemplate.builder().exponentialBackoff(10, 2, 500).build();
ExponentialBackOffPolicy policy = getPropertyValue(template, "backOffPolicy", ExponentialBackOffPolicy.class);

assertThat(policy.getInitialInterval()).isEqualTo(10);
assertThat(policy.getMultiplier()).isEqualTo(2);
assertThat(policy.getMaxInterval()).isEqualTo(500);
}

@Test
public void testExponentialBackoffDuration() {
RetryTemplate template = RetryTemplate.builder()
.exponentialBackoff(Duration.ofSeconds(2), 2, Duration.ofSeconds(3)).build();

ExponentialBackOffPolicy policy = getPropertyValue(template, "backOffPolicy", ExponentialBackOffPolicy.class);

assertThat(policy.getInitialInterval()).isEqualTo(2000);
assertThat(policy.getMultiplier()).isEqualTo(2);
assertThat(policy.getMaxInterval()).isEqualTo(3000);
assertThat(policy.getMaxInterval()).isEqualTo(3000);
}

@Test
public void testExpBackOffWithRandom() {
RetryTemplate template = RetryTemplate.builder().exponentialBackoff(10, 2, 500, true).build();
assertThat(getPropertyValue(template, "backOffPolicy")).isInstanceOf(ExponentialRandomBackOffPolicy.class);
}

@Test
public void testExponentialRandomBackoffDuration() {
RetryTemplate template = RetryTemplate.builder()
.exponentialBackoff(Duration.ofSeconds(2), 2, Duration.ofSeconds(3), true).build();

ExponentialRandomBackOffPolicy policy = getPropertyValue(template, "backOffPolicy",
ExponentialRandomBackOffPolicy.class);

assertThat(policy.getInitialInterval()).isEqualTo(2000);
assertThat(policy.getMultiplier()).isEqualTo(2);
assertThat(policy.getMaxInterval()).isEqualTo(3000);
}

@Test
public void testValidateInitAndMax() {
assertThatIllegalArgumentException()
Expand Down

0 comments on commit ff0588e

Please sign in to comment.