-
Notifications
You must be signed in to change notification settings - Fork 38.6k
Introduce minimal retry functionality as a core framework feature #34716
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
Conversation
92f257e
to
baf3703
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @fmbenhassine,
First and foremost, thanks for putting this PR together! 👍
I took a quick look, added a few comments, and asked a few questions (as food for thought).
And we will also discuss the proposal within the team.
Cheers,
Sam
spring-core/src/main/java/org/springframework/core/retry/RetryOperations.java
Outdated
Show resolved
Hide resolved
spring-core/src/main/java/org/springframework/core/retry/RetryPolicy.java
Outdated
Show resolved
Hide resolved
spring-core/src/main/java/org/springframework/core/retry/RetryPolicy.java
Outdated
Show resolved
Hide resolved
spring-core/src/main/java/org/springframework/core/retry/RetryOperations.java
Outdated
Show resolved
Hide resolved
spring-core/src/main/java/org/springframework/core/retry/RetryTemplate.java
Show resolved
Hide resolved
spring-core/src/main/java/org/springframework/core/retry/RetryTemplate.java
Outdated
Show resolved
Hide resolved
Thank you for the review, @sbrannen ! I added a couple of inline comments and I will update the PR accordingly. |
I updated the PR with the following changes:
I find this new version to be more coherent and consistent with other templates in terms of structure and API. Looking forward to the team's thoughts on this! |
5facde5
to
b7a7ca6
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is great even if I have left so many questions.
Thanks
spring-core/src/main/java/org/springframework/core/retry/RetryException.java
Show resolved
Hide resolved
spring-core/src/main/java/org/springframework/core/retry/RetryCallback.java
Outdated
Show resolved
Hide resolved
spring-core/src/main/java/org/springframework/core/retry/RetryTemplate.java
Outdated
Show resolved
Hide resolved
spring-core/src/main/java/org/springframework/core/retry/RetryTemplate.java
Outdated
Show resolved
Hide resolved
spring-core/src/test/java/org/springframework/core/retry/RetryTemplateTests.java
Outdated
Show resolved
Hide resolved
spring-core/src/main/java/org/springframework/core/retry/support/MaxRetryAttemptsPolicy.java
Outdated
Show resolved
Hide resolved
spring-core/src/main/java/org/springframework/core/retry/support/PredicateRetryPolicy.java
Outdated
Show resolved
Hide resolved
spring-core/src/main/java/org/springframework/util/backoff/ExponentialBackOffPolicy.java
Outdated
Show resolved
Hide resolved
...g-core/src/test/java/org/springframework/core/retry/support/MaxRetryDurationPolicyTests.java
Outdated
Show resolved
Hide resolved
spring-core/src/main/java/org/springframework/core/retry/support/MaxRetryAttemptsPolicy.java
Show resolved
Hide resolved
spring-core/src/main/java/org/springframework/core/retry/RetryExecution.java
Outdated
Show resolved
Hide resolved
Thank you for the review, @artembilan and @sbrannen ! I updated the PR accordingly and added a few comments. Please let me know if we need other updates. The build of the PR is failing for tests that are not related to this change set. |
spring-core/src/main/java/org/springframework/core/retry/support/CompositeRetryListener.java
Outdated
Show resolved
Hide resolved
...g-core/src/test/java/org/springframework/core/retry/support/MaxRetryAttemptsPolicyTests.java
Outdated
Show resolved
Hide resolved
👋🏻 Joining the conversation here as Spring Cloud is an advanced user of Spring Retry, so we would be interested in how the functionality compares to the Spring Retry project. |
This comment was marked as outdated.
This comment was marked as outdated.
spring-core/src/main/java/org/springframework/core/retry/support/PredicateRetryPolicy.java
Outdated
Show resolved
Hide resolved
This comment was marked as outdated.
This comment was marked as outdated.
spring-core/src/main/java/org/springframework/core/retry/support/MaxRetryAttemptsPolicy.java
Outdated
Show resolved
Hide resolved
spring-core/src/main/java/org/springframework/core/retry/RetryListener.java
Show resolved
Hide resolved
spring-core/src/main/java/org/springframework/core/retry/RetryListener.java
Outdated
Show resolved
Hide resolved
spring-core/src/main/java/org/springframework/core/retry/RetryTemplate.java
Show resolved
Hide resolved
spring-core/src/main/java/org/springframework/core/retry/RetryTemplate.java
Outdated
Show resolved
Hide resolved
This commit introduces a minimal core retry feature. It is inspired by Spring Retry, but redesigned and trimmed to the bare minimum to cover most cases.
b8454e2
to
3b68551
Compare
spring-core/src/main/java/org/springframework/core/retry/support/CompositeRetryListener.java
Show resolved
Hide resolved
This commit constitutes a first pass over the new core retry support. - Fix code and Javadoc formatting - Polish/fix Javadoc - Fix default FixedBackOff configuration in RetryTemplate - Consistent logging in RetryTemplate - Fix listener handling in CompositeRetryListener, allowing addListener() to work - Polish tests - Ensure RetryTemplateTests do not take over 30 seconds to execute See gh-34716
Due to lacking support in NullAway for the current arrangement, we are (perhaps temporarily) changing the signature of the execute() method in RetryOperations (and thus also in RetryTemplate)... from: <R extends @nullable Object> R execute(Retryable<R> retryable); to: <R> @nullable R execute(Retryable<? extends @nullable R> retryable); Once uber/NullAway#1075 has been resolved, we will consider switching back to the original signature. See gh-34716
After experimenting with our newly introduced core retry support (RetryPolicy, RetryTemplate, etc.) and @Retryable support, it became apparent that there are overlapping concerns between the current RetryPolicy and BackOff contracts. - RetryPolicy and BackOff both have stateful executions: RetryExecution and BackOffExecution. However, only one stateful execution is necessary. - FixedBackOff and ExponentialBackOff already incorporate "retry" logic in terms of max attempts, max elapsed time, etc. Thus, there is no need to duplicate such behavior in a RetryPolicy and its RetryExecution. - RetryTemplate currently accepts both a RetryPolicy and a BackOff in order to instrument the retry algorithm. However, users would probably rather focus on configuring all "retry" logic via a single mechanism. In light of the above, this commit directly incorporates BackOff in RetryPolicy as follows. - Remove the RetryExecution interface and move its shouldRetry() method to RetryPolicy, replacing the current RetryExecution start() method. - Introduce a default getBackOff() method in the RetryPolicy interface. - Introduce RetryPolicy.withDefaults() factory method. - Completely overhaul the RetryPolicy.Builder to provide support for configuring a BackOff strategy. - Remove BackOff configuration from RetryTemplate. - Revise the method signatures of callbacks in RetryListener. The collective result of these changes can be witnessed in the reworked implementation of AbstractRetryInterceptor. RetryPolicy retryPolicy = RetryPolicy.builder() .includes(spec.includes()) .excludes(spec.excludes()) .predicate(spec.predicate().forMethod(method)) .maxAttempts(spec.maxAttempts()) .delay(Duration.ofMillis(spec.delay())) .maxDelay(Duration.ofMillis(spec.maxDelay())) .jitter(Duration.ofMillis(spec.jitter())) .multiplier(spec.multiplier()) .build(); RetryTemplate retryTemplate = new RetryTemplate(retryPolicy); See spring-projectsgh-34716 See spring-projectsgh-34529 See spring-projectsgh-35058 Closes spring-projectsgh-35110
After experimenting with our newly introduced core retry support (RetryPolicy, RetryTemplate, etc.) and @Retryable support, it became apparent that there are overlapping concerns between the current RetryPolicy and BackOff contracts. - RetryPolicy and BackOff both have stateful executions: RetryExecution and BackOffExecution. However, only one stateful execution is necessary. - FixedBackOff and ExponentialBackOff already incorporate "retry" logic in terms of max attempts, max elapsed time, etc. Thus, there is no need to duplicate such behavior in a RetryPolicy and its RetryExecution. - RetryTemplate currently accepts both a RetryPolicy and a BackOff in order to instrument the retry algorithm. However, users would probably rather focus on configuring all "retry" logic via a single mechanism. In light of the above, this commit directly incorporates BackOff in RetryPolicy as follows. - Remove the RetryExecution interface and move its shouldRetry() method to RetryPolicy, replacing the current RetryExecution start() method. - Introduce a default getBackOff() method in the RetryPolicy interface. - Introduce RetryPolicy.withDefaults() factory method. - Completely overhaul the RetryPolicy.Builder to provide support for configuring a BackOff strategy. - Remove BackOff configuration from RetryTemplate. - Revise the method signatures of callbacks in RetryListener. The collective result of these changes can be witnessed in the reworked implementation of AbstractRetryInterceptor. RetryPolicy retryPolicy = RetryPolicy.builder() .includes(spec.includes()) .excludes(spec.excludes()) .predicate(spec.predicate().forMethod(method)) .maxAttempts(spec.maxAttempts()) .delay(Duration.ofMillis(spec.delay())) .maxDelay(Duration.ofMillis(spec.maxDelay())) .jitter(Duration.ofMillis(spec.jitter())) .multiplier(spec.multiplier()) .build(); RetryTemplate retryTemplate = new RetryTemplate(retryPolicy); See gh-34716 See gh-34529 See gh-35058 Closes gh-35110
This PR introduces a minimal core retry feature in Spring Framework. It is inspired by Spring Retry, but redesigned and trimmed to the bare minimum to cover most cases.
The main entry point is the
RetryTemplate
class, which is designed in a similar fashion to other templates provided by Spring. The package is minimal on purpose to keep its usage as simple as possible (see examples inRetryTemplateTests
). It focuses only on stateless retries for now, but can be extended with other retry operations as well.