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

Add builder for Backoff #5488

Merged
merged 20 commits into from
Feb 21, 2025
Merged

Add builder for Backoff #5488

merged 20 commits into from
Feb 21, 2025

Conversation

kth496
Copy link
Contributor

@kth496 kth496 commented Mar 6, 2024

Motivation:

Modifications:

  • Add Builder class for various backoff implementations.

Result:

return new Builder();
}

public static class Builder {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code style) We prefer top-level builder classes instead of nested classes.
Could you move this class to ExpontionalBackoffBuilder?

Comment on lines 99 to 101
public static Builder builder() {
return new Builder();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of adding a builder method to each implementation, should we add a builder method Backoff interface?

interface Backoff {
   static ExpontionalBackoffBuilder builderForExpontional() {
      ...
   }
}

Note that ExponentialBackoff is a package-private class that users can't access.

return new ExponentialBackoff(initialDelayMillis, maxDelayMillis, multiplier);
}

public Builder initialDelayMillis(long initialDelayMillis) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we make jitter values configured with this builder?

private long maxDelayMillis;

FibonacciBackoff build() {
return new FibonacciBackoff(initialDelayMillis, maxDelayMillis);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we migrate all factory methods where constructors are used into builder methods? e.g.

return new ExponentialBackoff(initialDelayMillis, maxDelayMillis, multiplier);

@kth496 kth496 force-pushed the add-builder-for-backoff branch from 35255b9 to 6ed81ab Compare March 19, 2024 04:50
@kth496
Copy link
Contributor Author

kth496 commented Mar 26, 2024

@ikhoon Thank you for your review. I will fix it within a week.

@kth496 kth496 marked this pull request as draft March 27, 2024 15:10
@github-actions github-actions bot added the Stale label Apr 27, 2024
@trustin
Copy link
Member

trustin commented May 8, 2024

@kth496 Looking forward to seeing more commits in this PR 💟

@github-actions github-actions bot removed the Stale label May 9, 2024
@trustin
Copy link
Member

trustin commented Jun 6, 2024

@kth496 Any updates?

@github-actions github-actions bot added the Stale label Jul 8, 2024
@github-actions github-actions bot removed the Stale label Aug 9, 2024
@github-actions github-actions bot added the Stale label Sep 10, 2024
@kth496
Copy link
Contributor Author

kth496 commented Oct 3, 2024

@ikhoon @trustin
Thanks for patience. I have improved the code based on your feedback:

  • Moved the nested classes into top-level classes
  • Moved the builder methods to the BackOff interface

Question:
Is there a good way to make the jitter value configurable in the builder? Since jitter can be commonly set across multiple BackOff implementations, I'm considering whether to define a separate higher-level builder.

@kth496 kth496 marked this pull request as ready for review October 3, 2024 07:28
Copy link

codecov bot commented Oct 3, 2024

Codecov Report

Attention: Patch coverage is 70.73171% with 12 lines in your changes missing coverage. Please review.

Project coverage is 74.69%. Comparing base (b2dcb3c) to head (343cbca).
Report is 39 commits behind head on main.

Files with missing lines Patch % Lines
...corp/armeria/client/retry/FixedBackoffBuilder.java 0.00% 5 Missing ⚠️
...rmeria/client/retry/ExponentialBackoffBuilder.java 75.00% 0 Missing and 3 partials ⚠️
...orp/armeria/client/retry/RandomBackoffBuilder.java 83.33% 0 Missing and 2 partials ⚠️
...ava/com/linecorp/armeria/client/retry/Backoff.java 75.00% 1 Missing ⚠️
.../armeria/client/retry/FibonacciBackoffBuilder.java 87.50% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##             main    #5488       +/-   ##
===========================================
+ Coverage        0   74.69%   +74.69%     
- Complexity      0    21721    +21721     
===========================================
  Files           0     1901     +1901     
  Lines           0    80424    +80424     
  Branches        0    10553    +10553     
===========================================
+ Hits            0    60069    +60069     
- Misses          0    15320    +15320     
- Partials        0     5035     +5035     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.


🚨 Try these New Features:

@kth496 kth496 requested a review from ikhoon October 5, 2024 12:52
*
* @see ExponentialBackoff
*/
public class ExponentialBackoffBuilder {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Global comments:

  • Add @UnstableApi to all new public classes.
  • Add final keyword for builder classes.
Suggested change
public class ExponentialBackoffBuilder {
@UnstableApi
public final class ExponentialBackoffBuilder {

*
* @return a newly created {@link ExponentialBackoff} with the configured delays and multiplier
*/
ExponentialBackoff build() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This must be public

Suggested change
ExponentialBackoff build() {
public ExponentialBackoff build() {

public class ExponentialBackoffBuilder {
private long initialDelayMillis;
private long maxDelayMillis;
private double multiplier;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we follow the default values used in the factory methods?

Suggested change
private double multiplier;
private double multiplier = 2.0;

@github-actions github-actions bot removed the Stale label Oct 12, 2024
@kth496 kth496 requested a review from ikhoon October 20, 2024 22:24
*
* @return a newly created {@link ExponentialBackoff} with the configured delays and multiplier
*/
public Backoff build() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code style) We conventionally place build() method on the bottom of a builder method. Would you move it below multiplier()?

}

/**
* Sets the maximum delay in milliseconds for the {@link FibonacciBackoff}.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FibonacciBackoff is an internal class to which we can't link in Javadoc.

Suggested change
* Sets the maximum delay in milliseconds for the {@link FibonacciBackoff}.
* Sets the maximum delay in milliseconds for the Fibonacci {@link Backoff}.

*
* @return a newly created {@link FixedBackoff} with the configured delay
*/
public Backoff build() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto. Please move to the bottom of this class.

}

/**
* Sets the delay duration in milliseconds for the {@link FixedBackoff}.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Sets the delay duration in milliseconds for the {@link FixedBackoff}.
* Sets the delay duration in milliseconds for the fixed {@link Backoff}.

*
* <pre>
* {@code
* FixedBackoff backoff = new FixedBackoffBuilder()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The constructor of FixedBackoffBuilder is now hidden.

Suggested change
* FixedBackoff backoff = new FixedBackoffBuilder()
* FixedBackoff backoff = Backoff.builderForFixed()

Comment on lines 53 to 54
*
* @return a newly created {@link FibonacciBackoff} with the configured delays
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems redundant.

Suggested change
*
* @return a newly created {@link FibonacciBackoff} with the configured delays

*
* <pre>
* {@code
* FibonacciBackoff backoff = new FibonacciBackoffBuilder()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto. Please use builder methods.

* @see ExponentialBackoff
*/
@UnstableApi
public final class ExponentialBackoffBuilder {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be worth allowing to configure jitter and max attempts in all builder methods.
What do you think of introducing AbstractBackoffBuilder to set them?

public abstract class AbstractBackoffBuilder<SELF extends AbstractBackoffBuilder<SELF>> {
    SELF jitter(double minJitterRate, double maxJitterRate, Supplier<Random> randomSupplier) {
        ... 
    }

    SELF maxAttempts(...) {
       ...
    }
}

public final class ExponentialBackoffBuilder 
    extends AbstractBackoffBuilder<ExponentialBackoffBuilder>{

    ...
}

@github-actions github-actions bot added the Stale label Nov 25, 2024
Comment on lines 68 to 82
abstract Backoff doBuild();

/**
* Builds and returns {@link Backoff} instance with configured properties.
*/
public final Backoff build() {
Backoff backoff = doBuild();
if (maxJitterRate > minJitterRate) {
backoff = new JitterAddingBackoff(backoff, minJitterRate, maxJitterRate, randomSupplier);
}
if (maxAttempts > 0) {
backoff = new AttemptLimitingBackoff(backoff, maxAttempts);
}
return backoff;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After much thought, I came up with the above solution. Is there a better way?

@kth496 kth496 requested a review from ikhoon January 27, 2025 13:29
@github-actions github-actions bot removed the Stale label Jan 30, 2025
Comment on lines 38 to 66
/**
* Sets the minimum and maximum jitter rates to apply to the delay.
*/
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.
*/
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
* .
*/
SELF maxAttempts(int maxAttempts) {
this.maxAttempts = maxAttempts;
return self();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question) Shouldn't these methods be public?

Comment on lines 75 to 80
if (maxJitterRate > minJitterRate) {
backoff = new JitterAddingBackoff(backoff, minJitterRate, maxJitterRate, randomSupplier);
}
if (maxAttempts > 0) {
backoff = new AttemptLimitingBackoff(backoff, maxAttempts);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we just check nullability to decide whether to apply a wrapping backoff?

e.g.

@Nullable
private Double minJitterRate;
...
if (minJitterRate != null && maxJitterRate != null) {
...
}

/**
* A skeletal builder implementation for {@link Backoff}.
*/
public abstract class AbstractBackoffBuilder<SELF extends AbstractBackoffBuilder<SELF>> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question) Does the abstract builder need to be public?

Suggested change
public abstract class AbstractBackoffBuilder<SELF extends AbstractBackoffBuilder<SELF>> {
abstract class AbstractBackoffBuilder<SELF extends AbstractBackoffBuilder<SELF>> {

@kth496 kth496 requested a review from jrhee17 February 10, 2025 23:22
@minwoox minwoox added this to the 1.32.0 milestone Feb 12, 2025
Comment on lines 44 to 45
private long initialDelayMillis;
private long maxDelayMillis;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you mind adding sensible default values for all the parameters in builders?

@kth496
Copy link
Contributor Author

kth496 commented Feb 12, 2025

@minwoox
Thank you for addressing the miscellaneous changes and committing them. I’ve also incorporated your additional review feedback!

*/
@UnstableApi
public final class ExponentialBackoffBuilder extends AbstractBackoffBuilder<ExponentialBackoffBuilder> {
private long initialDelayMillis = 100;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use 200:

static final String DEFAULT_BACKOFF_SPEC = "exponential=200:10000,jitter=0.2";

Comment on lines 43 to 44
private long initialDelayMillis;
private long maxDelayMillis;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you also add the default value for FibonacciBackoffBuilder, FixedBackoffBuilder, and RandomBackoffBuilder?

@kth496 kth496 requested a review from minwoox February 13, 2025 12:22
Copy link
Contributor

@ikhoon ikhoon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, @kth496! 👍🚀

Copy link
Contributor

@minwoox minwoox left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work, @kth496! 👏 👏 👏

@minwoox minwoox merged commit 98e3054 into line:main Feb 21, 2025
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add builder for Backoff
5 participants