mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-09-27 17:49:02 +00:00
Add reference documentation for @Retryable and @ConcurrencyLimit
See gh-35133 See gh-34529
This commit is contained in:
@@ -100,6 +100,7 @@
|
||||
*** xref:core/aop-api/autoproxy.adoc[]
|
||||
*** xref:core/aop-api/targetsource.adoc[]
|
||||
*** xref:core/aop-api/extensibility.adoc[]
|
||||
** xref:core/resilience.adoc[]
|
||||
** xref:core/null-safety.adoc[]
|
||||
** xref:core/databuffer-codec.adoc[]
|
||||
** xref:core/aot.adoc[]
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
[[resilience]]
|
||||
= Resilience Features
|
||||
|
||||
As of 7.0, the core Spring Framework includes a couple of common resilience features,
|
||||
in particular `@Retryable` and `@ConcurrencyLimit` annotations for method invocations.
|
||||
|
||||
|
||||
[[resilience-retryable]]
|
||||
== Using `@Retryable`
|
||||
|
||||
`@Retryable` is a common annotation specifying retry characteristics for an individual
|
||||
method (with the annotation declared at the method level), or for all proxy-invoked
|
||||
methods in a given class hierarchy (with the annotation declared at the type level).
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
@Retryable
|
||||
public void sendNotification() {
|
||||
this.jmsClient.destination("notifications").send(...);
|
||||
}
|
||||
----
|
||||
|
||||
By default, the method invocation will be retried for any exception thrown: with at
|
||||
most 3 retry attempts after an initial failure, and a delay of 1 second in-between.
|
||||
|
||||
This can be specifically adapted for every method if necessary, for example narrowing
|
||||
the exceptions to retry::
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
@Retryable(MessageDeliveryException.class)
|
||||
public void sendNotification() {
|
||||
this.jmsClient.destination("notifications").send(...);
|
||||
}
|
||||
----
|
||||
|
||||
Or for 5 retry attempts and an exponential back-off strategy with a bit of jitter:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
@Retryable(maxAttempts = 5, delay = 100, jitter = 10, multiplier = 2, maxDelay = 1000)
|
||||
public void sendNotification() {
|
||||
this.jmsClient.destination("notifications").send(...);
|
||||
}
|
||||
----
|
||||
|
||||
Last but not least, `@Retryable` also works for reactive methods with a reactive
|
||||
return type, decorating the pipeline with Reactor's retry capabilities:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
@Retryable(maxAttempts = 5, delay = 100, jitter = 10, multiplier = 2, maxDelay = 1000)
|
||||
public Mono<Void> sendNotification() {
|
||||
return Mono.from(...); // this raw Mono will get decorated with a retry spec
|
||||
}
|
||||
----
|
||||
|
||||
For details on the various characteristics, see the available annotation attributes
|
||||
on {spring-framework-api}/resilience/annotation/Retryable.html[`@Retryable`]. Note:
|
||||
There a String variants with placeholder support available for several attributes
|
||||
as well, as an alternative to the specifically typed annotation attributes above.
|
||||
|
||||
|
||||
[[resilience-concurrency]]
|
||||
== Using `@ConcurrencyLimit`
|
||||
|
||||
`@ConcurrencyLimit` is an annotation specifying a concurrency limit for an individual
|
||||
method (with the annotation declared at the method level), or for all proxy-invoked
|
||||
methods in a given class hierarchy (with the annotation declared at the type level).
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
@ConcurrencyLimit(10)
|
||||
public void sendNotification() {
|
||||
this.jmsClient.destination("notifications").send(...);
|
||||
}
|
||||
----
|
||||
|
||||
This is meant to protect the target resource from being accessed from too many
|
||||
threads at the same time, similar to the effect of a pool size limit in case of
|
||||
thread pool or of a connection pool that blocks access if its limit is reached.
|
||||
|
||||
At its most constrained, you may set the limit to 1, effectively locking access
|
||||
to the target bean instance:
|
||||
|
||||
[source,java,indent=0,subs="verbatim,quotes"]
|
||||
----
|
||||
@ConcurrencyLimit(1) // 1 is the default but this makes it more readable
|
||||
public void sendNotification() {
|
||||
this.jmsClient.destination("notifications").send(...);
|
||||
}
|
||||
----
|
||||
|
||||
Such limiting is particularly useful with Virtual Threads where there is generally
|
||||
no thread pool limit in place. For asynchronous tasks, this can be constrained on
|
||||
{spring-framework-api}/core/task/SimpleAsyncTaskExecutor.html[`SimpleAsyncTaskExecutor`].
|
||||
For synchronous invocations, this annotation provides equivalent behavior through
|
||||
{spring-framework-api}/aop/interceptor/ConcurrencyThrottleInterceptor.html[`ConcurrencyThrottleInterceptor`]
|
||||
which is available since Spring Framework 1.0 for programmatic use with the AOP framework.
|
||||
|
||||
|
||||
[[resilience-enable]]
|
||||
== Configuring `@EnableResilientMethods`
|
||||
|
||||
Note that like many of Spring's core annotation-based features, `@Retryable` and
|
||||
`@ConcurrencyLimit` are designed as metadata that you can choose to honor or ignore.
|
||||
The most convenient way of enabling actual processing of the resilience annotations
|
||||
through AOP interception is to declare `@EnableResilientMethods` on a corresponding
|
||||
configuration class. Alternatively, you may declare `RetryAnnotationBeanPostProcessor`
|
||||
and/or `ConcurrencyLimitBeanPostProcessor` individually.
|
||||
Reference in New Issue
Block a user