Inside a RetryTemplate the decision to retry
or fail in the execute method is determined by a
RetryPolicy which is also a factory for the
RetryContext. The
RetryTemplate has the responsibility to use the
current policy to create a RetryContext and pass
that in to the RetryCallback at every attempt.
After a callback fails the RetryTemplate has to
make a call to the RetryPolicy to ask it to update
its state (which will be stored in the
RetryContext), and then it asks the policy if
another attempt can be made. If another attempt cannot be made (e.g. a
limit is reached or a timeout is detected) then the policy is also
responsible for handling the exhausted state. Simple implementations will
just throw RetryExhaustedException which will cause
any enclosing transaction to be rolled back. More sophisticated
implementations might attempt to take some recovery action, in which case
the transaction can remain intact.
![]() | Tip |
|---|---|
Failures are inherently either retryable or not - if the same exception is always going to be thrown from the business logic, it doesn't help to retry it. So don't retry on all exception types - try to focus on only those exceptions that you expect to be retryable. It's not usually harmful to the business logic to retry more aggressively, but it's wasteful because if a failure is deterministic there will be time spent retrying something that you know in advance is fatal. |
Spring Batch provides some simple general purpose implementations of
stateless RetryPolicy, for example a
SimpleRetryPolicy, and the
TimeoutRetryPolicy used in the example
above.
The SimpleRetryPolicy just allows a retry on
any of a named list of exception types, up to a fixed number of times. It
also has a list of "fatal" exceptions that should never be retried, and
this list overrides the retryable list so that it can be used to give
finer control over the retry behavior:
SimpleRetryPolicy policy = new SimpleRetryPolicy();
// Set the max retry attempts
policy.setMaxAttempts(5);
// Retry on all exceptions (this is the default)
policy.setRetryableExceptions(new Class[] {Exception.class});
// ... but never retry IllegalStateException
policy.setFatalExceptions(new Class[] {IllegalStateException.class});
// Use the policy...
RetryTemplate template = new RetryTemplate();
template.setRetryPolicy(policy);
template.execute(new RetryCallback<Foo>() {
public Foo doWithRetry(RetryContext context) {
// business logic here
}
});There is also a more flexible implementation called
ExceptionClassifierRetryPolicy, which allows the
user to configure different retry behavior for an arbitrary set of
exception types though the ExceptionClassifier
abstraction. The policy works by calling on the classifier to convert an
exception into a delegate RetryPolicy, so for
example, one exception type can be retried more times before failure than
another by mapping it to a different policy.
Users might need to implement their own retry policies for more customized decisions. For instance, if there is a well-known, solution-specific, classification of exceptions into retryable and not retryable.