This commit reduces code duplication by reusing the logic already
available in ExceptionTypeFilter.
Closes gh-35109
Signed-off-by: Mengqi Xu <2663479778@qq.com>
When the core retry functionality was introduced, it had a built-in
MaxRetryDurationPolicy. In #35058, that was migrated to a
withMaxDuration() factory method, and in #35110 that was renamed to
withMaxElapsedTime() (with a corresponding maxElapsedTime() method on
the builder) in order to align with the maxElapsedTime feature of
ExponentialBackOff. The latter also changed the semantics of the
feature in the context of the RetryPolicy.
However, @Retryable does not provide maxElapsedTime support.
In addition, the maxElapsedTime feature is a bit misleading, since it
does not actually track CPU time or wall-clock time but rather only the
sum of individual, accumulated back-off intervals/delays, which is
likely not very useful. Furthermore, the maxElapsedTime will never
apply to a zero-valued delay/interval.
In light of the above, this commit removes the maxElapsedTime support
from the built-in RetryPolicy.
Users can still implement a custom BackOff strategy if they find they
need some form of "max elapsed time" or "max duration".
See gh-34716
See gh-35058
See gh-34529
See gh-35110
Closes gh-35144
Update `SpringFactoriesLoader` so that the cache stores only the
factories and not the complete loader.
Prior to this commit, if a cache entry was added with the thread
context classloader, the loader instance would be added and the
classloader stored. If the thread context classloader subsequently
changes, and a call is made to `forDefaultResourceLocation` with
`null` for the classloader, the cached entry would be used which
contains the older classloader.
Closes gh-34732
This commit simplifies our dependency management for JUnit artifacts by
making use of the junit-jupiter and junit-platform-suite aggregator
artifacts.
Closes gh-35127
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
gh-33616 refactored `CachingMetadataReaderFactory` and broke the
behavior as it bypassed the cache for `getMetadataReader(String
className)` operations.
This commit restores the original behavior.
Fixes gh-35112
Based on RetryTemplate with ExponentialBackOff.
Includes optional jitter support in ExponentialBackOff.
Supports reactive methods through Reactor's RetryBackoffSpec.
Closes gh-34529
Prior to this commit, we had three concrete RetryPolicy implementations.
- MaxRetryAttemptsPolicy
- MaxDurationAttemptsPolicy
- PredicateRetryPolicy
However, there was no way to combine the behavior of those policies.
Furthermore, the PredicateRetryPolicy was practically useless as a
standalone policy, since it did not have a way to end an infinite loop
for a Retryable that continually throws an exception which matches the
predicate.
This commit therefore replaces the current built-in RetryPolicy
implementations with a fluent Builder API and dedicated factory methods
for common use cases.
In addition, this commit also introduces built-in support for
specifying include/exclude lists.
Examples:
new MaxRetryAttemptsPolicy(5) -->
RetryPolicy.withMaxAttempts(5)
new MaxDurationAttemptsPolicy(Duration.ofSeconds(5)) -->
RetryPolicy.withMaxDuration(Duration.ofSeconds(5))
new PredicateRetryPolicy(IOException.class::isInstance) -->
RetryPolicy.builder()
.maxAttempts(3)
.predicate(IOException.class::isInstance)
.build();
The following example demonstrates all supported features of the builder.
RetryPolicy.builder()
.maxAttempts(5)
.maxDuration(Duration.ofMillis(100))
.includes(IOException.class)
.excludes(FileNotFoundException.class)
.predicate(t -> t.getMessage().contains("Unexpected failure"))
.build();
Closes gh-35058
Exposes last exception as cause in RetryException.
Applies first back-off after the initial exception.
Breaks out of retry loop on BackOffExecution.STOP.
Expects null result in Retryable and RetryListener.
Closes gh-35057
This commit configures a new CheckStyle rule that fails for empty
"catch" blocks, unless the exception is named "ignored" or "expected".
This also fixes the remaining instances missed by the previous commit.
Closes gh-35047
The Spring codebase sometimes ignores exceptions in catch blocks on
purpose. This is often called out by an inline comment.
We should make this more obvious by renaming the exception argument in
the catch block to declare whether the exception is "ignored" or
"expected".
See gh-35047
Signed-off-by: Vincent Potucek <vpotucek@me.com>
[brian.clozel@broadcom.com: rework commit message]
Signed-off-by: Brian Clozel <brian.clozel@broadcom.com>
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 https://github.com/uber/NullAway/issues/1075 has been resolved, we
will consider switching back to the original signature.
See gh-34716