diff --git a/core/spring-boot/src/main/java/org/springframework/boot/retry/RetryPolicySettings.java b/core/spring-boot/src/main/java/org/springframework/boot/retry/RetryPolicySettings.java index 6b406e2850c..80f6d7320bb 100644 --- a/core/spring-boot/src/main/java/org/springframework/boot/retry/RetryPolicySettings.java +++ b/core/spring-boot/src/main/java/org/springframework/boot/retry/RetryPolicySettings.java @@ -41,6 +41,12 @@ public final class RetryPolicySettings { */ public static final long DEFAULT_MAX_RETRIES = RetryPolicy.Builder.DEFAULT_MAX_RETRIES; + /** + * Default maximum elapsed time (infinite). + * @since 4.2.0 + */ + public static final Duration DEFAULT_TIMEOUT = RetryPolicy.Builder.DEFAULT_TIMEOUT; + /** * Default initial delay. */ @@ -64,6 +70,8 @@ public final class RetryPolicySettings { private Long maxRetries = DEFAULT_MAX_RETRIES; + private Duration timeout = DEFAULT_TIMEOUT; + private Duration delay = DEFAULT_DELAY; private @Nullable Duration jitter; @@ -85,6 +93,7 @@ public final class RetryPolicySettings { map.from(this::getExceptionExcludes).to(builder::excludes); map.from(this::getExceptionPredicate).to(builder::predicate); map.from(this::getMaxRetries).to(builder::maxRetries); + map.from(this::getTimeout).to(builder::timeout); map.from(this::getDelay).to(builder::delay); map.from(this::getJitter).to(builder::jitter); map.from(this::getMultiplier).to(builder::multiplier); @@ -168,6 +177,31 @@ public final class RetryPolicySettings { this.maxRetries = maxRetries; } + /** + * Return the timeout for the maximum amount of elapsed time allowed for the initial + * invocation and any subsequent retry attempts, including delays. + * @return the maximum duration the request can take + * @since 4.2.0 + */ + public Duration getTimeout() { + return this.timeout; + } + + /** + * Specify a timeout for the maximum amount of elapsed time allowed for the initial + * invocation and any subsequent retry attempts, including delays. + *

+ * The default is {@link Duration#ZERO}, which signals that no timeout should be + * applied. + * @param timeout the timeout, typically in milliseconds or seconds; must be greater + * than or equal to zero + * @since 4.2.0 + * @see #DEFAULT_TIMEOUT + */ + public void setTimeout(Duration timeout) { + this.timeout = timeout; + } + /** * Return the base delay after the initial invocation. * @return the base delay diff --git a/core/spring-boot/src/test/java/org/springframework/boot/retry/RetryPolicySettingsTests.java b/core/spring-boot/src/test/java/org/springframework/boot/retry/RetryPolicySettingsTests.java index cd42a3734ba..5ee43329536 100644 --- a/core/spring-boot/src/test/java/org/springframework/boot/retry/RetryPolicySettingsTests.java +++ b/core/spring-boot/src/test/java/org/springframework/boot/retry/RetryPolicySettingsTests.java @@ -115,6 +115,7 @@ class RetryPolicySettingsTests { void createRetryPolicyWithDefaultsMatchesBackOffDefaults() { RetryPolicy defaultRetryPolicy = RetryPolicy.builder().build(); RetryPolicy retryPolicy = new RetryPolicySettings().createRetryPolicy(); + assertThat(retryPolicy.getTimeout()).isEqualByComparingTo(defaultRetryPolicy.getTimeout()); assertThat(retryPolicy.getBackOff()).isInstanceOf(ExponentialBackOff.class); ExponentialBackOff defaultBackOff = (ExponentialBackOff) defaultRetryPolicy.getBackOff(); ExponentialBackOff backOff = (ExponentialBackOff) retryPolicy.getBackOff(); @@ -129,11 +130,13 @@ class RetryPolicySettingsTests { void createRetryPolicyWithCustomAttributes() { RetryPolicySettings settings = new RetryPolicySettings(); settings.setMaxRetries(10L); + settings.setTimeout(Duration.ofHours(1)); settings.setDelay(Duration.ofSeconds(2)); settings.setJitter(Duration.ofMillis(500)); settings.setMultiplier(2.0); settings.setMaxDelay(Duration.ofSeconds(20)); RetryPolicy retryPolicy = settings.createRetryPolicy(); + assertThat(retryPolicy.getTimeout()).isEqualTo(Duration.ofHours(1)); assertThat(retryPolicy.getBackOff()).isInstanceOfSatisfying(ExponentialBackOff.class, (backOff) -> { assertThat(backOff.getMaxAttempts()).isEqualTo(10); assertThat(backOff.getInitialInterval()).isEqualTo(2000);