Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make RetryBackoffSpec Multiplier configurable #3603

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 3 additions & 3 deletions reactor-core/src/main/java/reactor/util/retry/Retry.java
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2021 VMware Inc. or its affiliates, All Rights Reserved.
* Copyright (c) 2020-2023 VMware Inc. or its affiliates, All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -165,7 +165,7 @@ default RetrySignal copy() {
* @see RetryBackoffSpec#minBackoff(Duration)
*/
public static RetryBackoffSpec backoff(long maxAttempts, Duration minBackoff) {
return new RetryBackoffSpec(Context.empty(), maxAttempts, t -> true, false, minBackoff, MAX_BACKOFF, 0.5d, Schedulers::parallel,
return new RetryBackoffSpec(Context.empty(), maxAttempts, t -> true, false, minBackoff, MAX_BACKOFF, 2, 0.5d, Schedulers::parallel,
NO_OP_CONSUMER, NO_OP_CONSUMER, NO_OP_BIFUNCTION, NO_OP_BIFUNCTION,
RetryBackoffSpec.BACKOFF_EXCEPTION_GENERATOR);
}
Expand All @@ -187,7 +187,7 @@ public static RetryBackoffSpec backoff(long maxAttempts, Duration minBackoff) {
* @see RetryBackoffSpec#maxBackoff(Duration)
*/
public static RetryBackoffSpec fixedDelay(long maxAttempts, Duration fixedDelay) {
return new RetryBackoffSpec(Context.empty(), maxAttempts, t -> true, false, fixedDelay, fixedDelay, 0d, Schedulers::parallel,
return new RetryBackoffSpec(Context.empty(), maxAttempts, t -> true, false, fixedDelay, fixedDelay, 2, 0d, Schedulers::parallel,
NO_OP_CONSUMER, NO_OP_CONSUMER, NO_OP_BIFUNCTION, NO_OP_BIFUNCTION,
RetryBackoffSpec.BACKOFF_EXCEPTION_GENERATOR);
}
Expand Down
Expand Up @@ -83,6 +83,12 @@ public final class RetryBackoffSpec extends Retry {
*/
public final Duration maxBackoff;

/**
* The configured multiplier, as a {@code double}.
* @see #multiplier(double)
*/
public final double multiplier;

/**
* The configured jitter factor, as a {@code double}.
* @see #jitter(double)
Expand Down Expand Up @@ -130,7 +136,8 @@ public final class RetryBackoffSpec extends Retry {
long max,
Predicate<? super Throwable> aThrowablePredicate,
boolean isTransientErrors,
Duration minBackoff, Duration maxBackoff, double jitterFactor,
Duration minBackoff, Duration maxBackoff,
double multiplier, double jitterFactor,
Supplier<Scheduler> backoffSchedulerSupplier,
Consumer<RetrySignal> doPreRetry,
Consumer<RetrySignal> doPostRetry,
Expand All @@ -143,6 +150,7 @@ public final class RetryBackoffSpec extends Retry {
this.isTransientErrors = isTransientErrors;
this.minBackoff = minBackoff;
this.maxBackoff = maxBackoff;
this.multiplier = multiplier > 1.0 ? multiplier : 1;
this.jitterFactor = jitterFactor;
this.backoffSchedulerSupplier = backoffSchedulerSupplier;
this.syncPreRetry = doPreRetry;
Expand All @@ -166,6 +174,7 @@ public RetryBackoffSpec withRetryContext(ContextView retryContext) {
this.isTransientErrors,
this.minBackoff,
this.maxBackoff,
this.multiplier,
this.jitterFactor,
this.backoffSchedulerSupplier,
this.syncPreRetry,
Expand All @@ -191,6 +200,7 @@ public RetryBackoffSpec maxAttempts(long maxAttempts) {
this.isTransientErrors,
this.minBackoff,
this.maxBackoff,
this.multiplier,
this.jitterFactor,
this.backoffSchedulerSupplier,
this.syncPreRetry,
Expand All @@ -216,6 +226,7 @@ public RetryBackoffSpec filter(Predicate<? super Throwable> errorFilter) {
this.isTransientErrors,
this.minBackoff,
this.maxBackoff,
this.multiplier,
this.jitterFactor,
this.backoffSchedulerSupplier,
this.syncPreRetry,
Expand Down Expand Up @@ -256,6 +267,7 @@ public RetryBackoffSpec modifyErrorFilter(
this.isTransientErrors,
this.minBackoff,
this.maxBackoff,
this.multiplier,
this.jitterFactor,
this.backoffSchedulerSupplier,
this.syncPreRetry,
Expand Down Expand Up @@ -283,6 +295,7 @@ public RetryBackoffSpec doBeforeRetry(
this.isTransientErrors,
this.minBackoff,
this.maxBackoff,
this.multiplier,
this.jitterFactor,
this.backoffSchedulerSupplier,
this.syncPreRetry.andThen(doBeforeRetry),
Expand All @@ -309,6 +322,7 @@ public RetryBackoffSpec doAfterRetry(Consumer<RetrySignal> doAfterRetry) {
this.isTransientErrors,
this.minBackoff,
this.maxBackoff,
this.multiplier,
this.jitterFactor,
this.backoffSchedulerSupplier,
this.syncPreRetry,
Expand All @@ -334,6 +348,7 @@ public RetryBackoffSpec doBeforeRetryAsync(
this.isTransientErrors,
this.minBackoff,
this.maxBackoff,
this.multiplier,
this.jitterFactor,
this.backoffSchedulerSupplier,
this.syncPreRetry,
Expand All @@ -359,6 +374,7 @@ public RetryBackoffSpec doAfterRetryAsync(
this.isTransientErrors,
this.minBackoff,
this.maxBackoff,
this.multiplier,
this.jitterFactor,
this.backoffSchedulerSupplier,
this.syncPreRetry,
Expand Down Expand Up @@ -389,6 +405,7 @@ public RetryBackoffSpec onRetryExhaustedThrow(BiFunction<RetryBackoffSpec, Retry
this.isTransientErrors,
this.minBackoff,
this.maxBackoff,
this.multiplier,
this.jitterFactor,
this.backoffSchedulerSupplier,
this.syncPreRetry,
Expand Down Expand Up @@ -419,6 +436,7 @@ public RetryBackoffSpec transientErrors(boolean isTransientErrors) {
isTransientErrors,
this.minBackoff,
this.maxBackoff,
this.multiplier,
this.jitterFactor,
this.backoffSchedulerSupplier,
this.syncPreRetry,
Expand All @@ -444,6 +462,7 @@ public RetryBackoffSpec minBackoff(Duration minBackoff) {
this.isTransientErrors,
minBackoff,
this.maxBackoff,
this.multiplier,
this.jitterFactor,
this.backoffSchedulerSupplier,
this.syncPreRetry,
Expand All @@ -469,6 +488,7 @@ public RetryBackoffSpec maxBackoff(Duration maxBackoff) {
this.isTransientErrors,
this.minBackoff,
maxBackoff,
this.multiplier,
this.jitterFactor,
this.backoffSchedulerSupplier,
this.syncPreRetry,
Expand All @@ -495,6 +515,7 @@ public RetryBackoffSpec jitter(double jitterFactor) {
this.isTransientErrors,
this.minBackoff,
this.maxBackoff,
this.multiplier,
jitterFactor,
this.backoffSchedulerSupplier,
this.syncPreRetry,
Expand All @@ -504,6 +525,32 @@ public RetryBackoffSpec jitter(double jitterFactor) {
this.retryExhaustedGenerator);
}

/**
* Set a multiplier for exponential backoffs that is used as the base for each backoff. This method switches to an
* exponential backoff strategy with a zero minimum backoff if not already a backoff strategy.
* Defaults to {@code 2}.
*
* @param multiplier the new multiplier as a {@code double}
* @return a new copy of the {@link RetryBackoffSpec} which can either be further configured or used as {@link Retry}
*/
public RetryBackoffSpec multiplier(double multiplier) {
return new RetryBackoffSpec(
this.retryContext,
this.maxAttempts,
this.errorFilter,
this.isTransientErrors,
this.minBackoff,
this.maxBackoff,
multiplier,
this.jitterFactor,
this.backoffSchedulerSupplier,
this.syncPreRetry,
this.syncPostRetry,
this.asyncPreRetry,
this.asyncPostRetry,
this.retryExhaustedGenerator);
}

/**
* Set a {@link Scheduler} on which to execute the delays computed by the exponential backoff
* strategy. Defaults to a deferred resolution of the current {@link Schedulers#parallel()} (use
Expand All @@ -520,6 +567,7 @@ public RetryBackoffSpec scheduler(@Nullable Scheduler backoffScheduler) {
this.isTransientErrors,
this.minBackoff,
this.maxBackoff,
this.multiplier,
this.jitterFactor,
backoffScheduler == null ? Schedulers::parallel : () -> backoffScheduler,
this.syncPreRetry,
Expand Down Expand Up @@ -562,7 +610,7 @@ public Flux<Long> generateCompanion(Flux<RetrySignal> t) {

Duration nextBackoff;
try {
nextBackoff = minBackoff.multipliedBy((long) Math.pow(2, iteration));
nextBackoff = minBackoff.multipliedBy((long) Math.pow(multiplier, iteration));
if (nextBackoff.compareTo(maxBackoff) > 0) {
nextBackoff = maxBackoff;
}
Expand Down
Expand Up @@ -46,6 +46,7 @@ public void builderMethodsProduceNewInstances() {
assertThat(init)
.isNotSameAs(init.minBackoff(Duration.ofSeconds(1)))
.isNotSameAs(init.maxBackoff(Duration.ZERO))
.isNotSameAs(init.multiplier(2))
.isNotSameAs(init.jitter(0.5d))
.isNotSameAs(init.scheduler(Schedulers.parallel()))
.isNotSameAs(init.maxAttempts(10))
Expand Down