Annotation Type Retry
retryOnStatus(), up to
times() attempts total, waiting delayMillis() between
attempts and multiplying that wait by backoffMultiplier() after
each one - unless the failed response itself carries a Retry-After
header, which takes priority over the computed delay for that one wait
(see delayMillis()), and jitterFactor() randomizes each
computed delay to avoid many callers retrying in lockstep.
Works on both a synchronous return type and a CompletableFuture
one - the async case schedules each retry on a background thread instead
of blocking the caller. Every attempt, including ones that get retried,
is still reported to any registered RequestInterceptor's
afterResponse.
Retrying is only safe by default for a method whose HTTP verb is already
idempotent (GET/PUT/DELETE) - retrying a
POST/PATCH that actually succeeded server-side but whose
response was lost in transit (a timeout or dropped connection after the
server committed) risks double-executing it (a duplicate charge, a
duplicate order). idempotent() closes that gap: it generates one
Idempotency-Key header value and holds it identical across every
attempt of a given call, so a server that honors idempotency keys (as
Stripe, PayPal, Adyen, and Square all do) can recognize a retried attempt
as the same logical request instead of a new one.
Also valid directly on a @RestClient interface, as a default for
every method that doesn't declare its own @Retry - mirroring
@BaseUrl's own interface-level-default/per-method-override shape,
for an interface that wants one uniform retry policy instead of repeating
the same annotation on every method. A method's own @Retry, if
present, is used in full instead of the interface's - the two are never
merged field-by-field.
-
Optional Element Summary
Optional ElementsModifier and TypeOptional ElementDescriptiondoubleThe factor the delay is multiplied by after each retry -1.0for a fixed delay, greater than1.0for exponential backoff.longHow long to wait before the first retry, in milliseconds - overridden for that one wait whenever the response being retried carries aRetry-Afterheader (as a delta-seconds value or an HTTP-date), since the server's own stated wait time is more authoritative than a value fixed at compile time.booleanIf true, sends anIdempotency-Keyheader - one randomly generated value per call, held identical across every retry attempt of that call (never regenerated between attempts, never shared with any other call) - the standard way (Stripe, PayPal, Adyen, Square) to let a server tell a genuine retry of the same request apart from a new one.doubleRandomizes each computed delay (not one taken from aRetry-Afterheader, which is already an explicit server instruction) by up to this fraction in either direction, so that many callers who all started retrying at the same moment - e.g. every replica of a horizontally-scaled service hitting the same downstream - don't retry in exact lockstep.int[]The HTTP status codes that count as a failure worth retrying.intHow many attempts to make in total before giving up and returning (or throwing) the last outcome.
-
Element Details
-
times
int timesHow many attempts to make in total before giving up and returning (or throwing) the last outcome. Must be at least 1.- Returns:
- the maximum number of attempts
- Default:
- 3
-
delayMillis
long delayMillisHow long to wait before the first retry, in milliseconds - overridden for that one wait whenever the response being retried carries aRetry-Afterheader (as a delta-seconds value or an HTTP-date), since the server's own stated wait time is more authoritative than a value fixed at compile time. A transport failure (no response at all) has no header to read, so it always falls back to this value.- Returns:
- the initial delay in milliseconds
- Default:
- 200L
-
backoffMultiplier
double backoffMultiplierThe factor the delay is multiplied by after each retry -1.0for a fixed delay, greater than1.0for exponential backoff. Applied to the previous attempt's own delay, whether that delay came from this computation or from aRetry-Afterheader.- Returns:
- the backoff multiplier
- Default:
- 2.0
-
jitterFactor
double jitterFactorRandomizes each computed delay (not one taken from aRetry-Afterheader, which is already an explicit server instruction) by up to this fraction in either direction, so that many callers who all started retrying at the same moment - e.g. every replica of a horizontally-scaled service hitting the same downstream - don't retry in exact lockstep.0.0(the default) applies no jitter, exactly reproducing the delay sequencedelayMillis()/backoffMultiplier()alone would produce;1.0allows the delay to be scaled anywhere from zero to double. Must be between0.0and1.0inclusive.- Returns:
- the jitter fraction
- Default:
- 0.0
-
retryOnStatus
int[] retryOnStatusThe HTTP status codes that count as a failure worth retrying. A transport error (no response at all) is always retried regardless of this list.- Returns:
- the retryable status codes
- Default:
- {429, 502, 503, 504}
-
idempotent
boolean idempotentIf true, sends anIdempotency-Keyheader - one randomly generated value per call, held identical across every retry attempt of that call (never regenerated between attempts, never shared with any other call) - the standard way (Stripe, PayPal, Adyen, Square) to let a server tell a genuine retry of the same request apart from a new one. Most meaningful onPOST/PATCH, the two methods HTTP itself doesn't already guarantee are safe to retry; harmless (but redundant) onGET/PUT/DELETE.- Returns:
- whether to send a stable
Idempotency-Key
- Default:
- false
-