-
Notifications
You must be signed in to change notification settings - Fork 935
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Motivation: - #5483 Modifications: - Add `Builder` class for various backoff implementations. Result: - Closes #5483 - Will be able to use the builder class to create instances of BackOff.
- Loading branch information
Showing
10 changed files
with
612 additions
and
0 deletions.
There are no files selected for viewing
92 changes: 92 additions & 0 deletions
92
core/src/main/java/com/linecorp/armeria/client/retry/AbstractBackoffBuilder.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
/* | ||
* Copyright 2024 LY Corporation | ||
* | ||
* LY Corporation licenses this file to you under the Apache License, | ||
* version 2.0 (the "License"); you may not use this file except in compliance | ||
* with the License. You may obtain a copy of the License at: | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
* License for the specific language governing permissions and limitations | ||
* under the License. | ||
*/ | ||
package com.linecorp.armeria.client.retry; | ||
|
||
import static java.util.Objects.requireNonNull; | ||
|
||
import java.util.Random; | ||
import java.util.concurrent.ThreadLocalRandom; | ||
import java.util.function.Supplier; | ||
|
||
import com.linecorp.armeria.common.annotation.Nullable; | ||
|
||
/** | ||
* A skeletal builder implementation for {@link Backoff}. | ||
*/ | ||
abstract class AbstractBackoffBuilder<SELF extends AbstractBackoffBuilder<SELF>> { | ||
@Nullable | ||
private Double minJitterRate; | ||
@Nullable | ||
private Double maxJitterRate; | ||
@Nullable | ||
private Integer maxAttempts; | ||
@Nullable | ||
private Supplier<Random> randomSupplier; | ||
|
||
@SuppressWarnings("unchecked") | ||
private SELF self() { | ||
return (SELF) this; | ||
} | ||
|
||
/** | ||
* Sets the minimum and maximum jitter rates to apply to the delay. | ||
*/ | ||
public final SELF jitter(double minJitterRate, double maxJitterRate) { | ||
this.minJitterRate = minJitterRate; | ||
this.maxJitterRate = maxJitterRate; | ||
return self(); | ||
} | ||
|
||
/** | ||
* Sets the minimum and maximum jitter rates to apply to the delay, as well as a | ||
* custom {@link Random} supplier for generating the jitter. | ||
*/ | ||
public final SELF jitter(double minJitterRate, double maxJitterRate, Supplier<Random> randomSupplier) { | ||
requireNonNull(randomSupplier, "randomSupplier"); | ||
this.minJitterRate = minJitterRate; | ||
this.maxJitterRate = maxJitterRate; | ||
this.randomSupplier = randomSupplier; | ||
return self(); | ||
} | ||
|
||
/** | ||
* Sets the maximum number of attempts. | ||
*/ | ||
public final SELF maxAttempts(int maxAttempts) { | ||
this.maxAttempts = maxAttempts; | ||
return self(); | ||
} | ||
|
||
abstract Backoff doBuild(); | ||
|
||
/** | ||
* Builds and returns {@link Backoff} instance with configured properties. | ||
*/ | ||
public final Backoff build() { | ||
Backoff backoff = doBuild(); | ||
if (minJitterRate != null && maxJitterRate != null) { | ||
Supplier<Random> randomSupplier = this.randomSupplier; | ||
if (randomSupplier == null) { | ||
randomSupplier = ThreadLocalRandom::current; | ||
} | ||
backoff = new JitterAddingBackoff(backoff, minJitterRate, maxJitterRate, randomSupplier); | ||
} | ||
if (maxAttempts != null) { | ||
backoff = new AttemptLimitingBackoff(backoff, maxAttempts); | ||
} | ||
return backoff; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
103 changes: 103 additions & 0 deletions
103
core/src/main/java/com/linecorp/armeria/client/retry/ExponentialBackoffBuilder.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
/* | ||
* Copyright 2024 LY Corporation | ||
* | ||
* LY Corporation licenses this file to you under the Apache License, | ||
* version 2.0 (the "License"); you may not use this file except in compliance | ||
* with the License. You may obtain a copy of the License at: | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
* License for the specific language governing permissions and limitations | ||
* under the License. | ||
*/ | ||
package com.linecorp.armeria.client.retry; | ||
|
||
import static com.google.common.base.Preconditions.checkArgument; | ||
|
||
import com.linecorp.armeria.common.annotation.UnstableApi; | ||
|
||
/** | ||
* A builder for creating instances of Exponential {@link Backoff}. | ||
* | ||
* <p>This builder allows you to configure an exponential backoff strategy by specifying | ||
* the initial delay, the maximum delay, and a multiplier. The exponential backoff | ||
* increases the delay between retries exponentially, starting from the initial delay and | ||
* multiplying the delay by the specified multiplier after each retry, up to the maximum delay.</p> | ||
* | ||
* <p>Example usage:</p> | ||
* | ||
* <pre> | ||
* {@code | ||
* Backoff backoff = Backoff.builderForExponential() | ||
* .initialDelayMillis(200) | ||
* .maxDelayMillis(10000) | ||
* .multiplier(2.0) | ||
* .build(); | ||
* } | ||
* </pre> | ||
*/ | ||
@UnstableApi | ||
public final class ExponentialBackoffBuilder extends AbstractBackoffBuilder<ExponentialBackoffBuilder> { | ||
|
||
static final long DEFAULT_INITIAL_DELAY_MILLIS = 200; | ||
static final long DEFAULT_MAX_DELAY_MILLIS = 10000; | ||
static final double DEFAULT_MULTIPLIER = 2.0; | ||
|
||
private long initialDelayMillis = DEFAULT_INITIAL_DELAY_MILLIS; | ||
private long maxDelayMillis = DEFAULT_MAX_DELAY_MILLIS; | ||
private double multiplier = DEFAULT_MULTIPLIER; | ||
|
||
ExponentialBackoffBuilder() {} | ||
|
||
/** | ||
* Sets the initial delay in milliseconds for the Exponential {@link Backoff}. | ||
* | ||
* <p>The initial delay is the starting value for the exponential backoff, determining | ||
* the delay before the first retry. Subsequent delays will increase exponentially | ||
* based on the multiplier.</p> | ||
* | ||
* @param initialDelayMillis the initial delay in milliseconds | ||
*/ | ||
public ExponentialBackoffBuilder initialDelayMillis(long initialDelayMillis) { | ||
checkArgument(initialDelayMillis >= 0, "initialDelayMillis: %s (expected: >= 0)", initialDelayMillis); | ||
this.initialDelayMillis = initialDelayMillis; | ||
return this; | ||
} | ||
|
||
/** | ||
* Sets the maximum delay in milliseconds for the Exponential {@link Backoff}. | ||
* | ||
* <p>The maximum delay is the upper limit for the backoff delay. Once the delay reaches | ||
* this value, it will not increase further, even if the multiplier would result in a higher value.</p> | ||
* | ||
* @param maxDelayMillis the maximum delay in milliseconds | ||
*/ | ||
public ExponentialBackoffBuilder maxDelayMillis(long maxDelayMillis) { | ||
checkArgument(maxDelayMillis >= 0, "maxDelayMillis: %s (expected: >= 0)", maxDelayMillis); | ||
this.maxDelayMillis = maxDelayMillis; | ||
return this; | ||
} | ||
|
||
/** | ||
* Sets the multiplier for the Exponential {@link Backoff}. | ||
* | ||
* <p>The multiplier controls how much the delay increases after each retry. | ||
* The delay for each retry is determined by multiplying the previous delay by this value, | ||
* until the maximum delay is reached.</p> | ||
* | ||
* @param multiplier the multiplier for the exponential backoff | ||
*/ | ||
public ExponentialBackoffBuilder multiplier(double multiplier) { | ||
checkArgument(multiplier > 1.0, "multiplier: %s (expected: > 1.0)", multiplier); | ||
this.multiplier = multiplier; | ||
return this; | ||
} | ||
|
||
@Override | ||
Backoff doBuild() { | ||
return new ExponentialBackoff(initialDelayMillis, maxDelayMillis, multiplier); | ||
} | ||
} |
87 changes: 87 additions & 0 deletions
87
core/src/main/java/com/linecorp/armeria/client/retry/FibonacciBackoffBuilder.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
/* | ||
* Copyright 2024 LY Corporation | ||
* | ||
* LY Corporation licenses this file to you under the Apache License, | ||
* version 2.0 (the "License"); you may not use this file except in compliance | ||
* with the License. You may obtain a copy of the License at: | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
* License for the specific language governing permissions and limitations | ||
* under the License. | ||
*/ | ||
package com.linecorp.armeria.client.retry; | ||
|
||
import static com.google.common.base.Preconditions.checkArgument; | ||
|
||
import com.linecorp.armeria.common.annotation.UnstableApi; | ||
|
||
/** | ||
* A builder for creating instances of Fibonacci {@link Backoff}. | ||
* | ||
* <p>This builder allows you to configure a Fibonacci backoff strategy by specifying | ||
* an initial delay and a maximum delay in milliseconds. The Fibonacci backoff strategy | ||
* increases the delay between retries according to the Fibonacci sequence, while respecting | ||
* the configured maximum delay.</p> | ||
* | ||
* <p>Example usage:</p> | ||
* | ||
* <pre> | ||
* {@code | ||
* Backoff backoff = Backoff.builderForFibonacci() | ||
* .initialDelayMillis(200) | ||
* .maxDelayMillis(10000) | ||
* .build(); | ||
* } | ||
* </pre> | ||
*/ | ||
@UnstableApi | ||
public final class FibonacciBackoffBuilder extends AbstractBackoffBuilder<FibonacciBackoffBuilder> { | ||
|
||
static final long DEFAULT_INITIAL_DELAY_MILLIS = 200; | ||
static final long DEFAULT_MAX_DELAY_MILLIS = 10000; | ||
|
||
private long initialDelayMillis = 200; | ||
private long maxDelayMillis = 10000; | ||
|
||
FibonacciBackoffBuilder() {} | ||
|
||
/** | ||
* Sets the initial delay in milliseconds for the Fibonacci {@link Backoff}. | ||
* | ||
* <p>The initial delay is the base value from which the Fibonacci sequence will start, | ||
* and it determines the delay before the first retry.</p> | ||
* | ||
* @param initialDelayMillis the initial delay in milliseconds | ||
*/ | ||
public FibonacciBackoffBuilder initialDelayMillis(long initialDelayMillis) { | ||
checkArgument(initialDelayMillis >= 0, | ||
"initialDelayMillis: %s (expected: >= 0)", initialDelayMillis); | ||
|
||
this.initialDelayMillis = initialDelayMillis; | ||
return this; | ||
} | ||
|
||
/** | ||
* Sets the maximum delay in milliseconds for the Fibonacci {@link Backoff}. | ||
* | ||
* <p>The maximum delay sets an upper limit to the delays generated by the Fibonacci | ||
* sequence. Once the delays reach this value, they will not increase further.</p> | ||
* | ||
* @param maxDelayMillis the maximum delay in milliseconds | ||
*/ | ||
public FibonacciBackoffBuilder maxDelayMillis(long maxDelayMillis) { | ||
checkArgument(maxDelayMillis >= 0, | ||
"maxDelayMillis: %s (expected: >= 0)", maxDelayMillis); | ||
this.maxDelayMillis = maxDelayMillis; | ||
return this; | ||
} | ||
|
||
@Override | ||
Backoff doBuild() { | ||
return new FibonacciBackoff(initialDelayMillis, maxDelayMillis); | ||
} | ||
} |
Oops, something went wrong.