diff --git a/core/src/main/java/dev/failsafe/RetryPolicyBuilder.java b/core/src/main/java/dev/failsafe/RetryPolicyBuilder.java index a28e5237..0a18090d 100644 --- a/core/src/main/java/dev/failsafe/RetryPolicyBuilder.java +++ b/core/src/main/java/dev/failsafe/RetryPolicyBuilder.java @@ -313,6 +313,16 @@ public RetryPolicyBuilder withBackoff(Duration delay, Duration maxDelay, doub return this; } + /** + * If a backoff delay factor is given, the delay will be reset to the initial delay when a task attempt has been + * running without error for the given duration. This can be used for long-running tasks that can continue their work + * after a period with network issues for example. + */ + public RetryPolicyBuilder withBackoffResetAfter(Duration backoffReset) { + config.backoffReset = backoffReset; + return this; + } + /** * Sets the {@code delay} to occur between retries. Replaces any previously configured {@link #withBackoff(Duration, * Duration) backoff} or {@link #withDelay(Duration, Duration) random} delays. diff --git a/core/src/main/java/dev/failsafe/RetryPolicyConfig.java b/core/src/main/java/dev/failsafe/RetryPolicyConfig.java index 956fb1c9..acae37c9 100644 --- a/core/src/main/java/dev/failsafe/RetryPolicyConfig.java +++ b/core/src/main/java/dev/failsafe/RetryPolicyConfig.java @@ -41,6 +41,7 @@ public class RetryPolicyConfig extends DelayablePolicyConfig { Duration delayMin; Duration delayMax; double delayFactor; + Duration backoffReset; Duration maxDelay; Duration jitter; double jitterFactor; @@ -63,6 +64,7 @@ public class RetryPolicyConfig extends DelayablePolicyConfig { delayMin = config.delayMin; delayMax = config.delayMax; delayFactor = config.delayFactor; + backoffReset = config.backoffReset; maxDelay = config.maxDelay; jitter = config.jitter; jitterFactor = config.jitterFactor; @@ -146,6 +148,15 @@ public double getDelayFactor() { return delayFactor; } + /** + * Returns the duration after which the backoff delay will be reset + * + * @see RetryPolicyBuilder#withBackoffResetAfter(Duration) + */ + public Duration getBackoffReset() { + return backoffReset; + } + /** * Returns the jitter, else {@code null} if none has been configured. * diff --git a/core/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java b/core/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java index 60d24005..c8ae9578 100644 --- a/core/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java +++ b/core/src/main/java/dev/failsafe/internal/RetryPolicyExecutor.java @@ -279,6 +279,9 @@ else if (delayMin != null && delayMax != null) } private long adjustForBackoff(ExecutionContext context, long delayNanos) { + if (config.getBackoffReset() != null && context.getElapsedAttemptTime().compareTo(config.getBackoffReset()) >= 0) { + return config.getDelay().toNanos(); + } if (context.getAttemptCount() != 1 && config.getMaxDelay() != null) delayNanos = (long) Math.min(delayNanos * config.getDelayFactor(), config.getMaxDelay().toNanos()); return delayNanos;