Skip to main content

RetryConfig

Struct RetryConfig 

Source
pub struct RetryConfig {
    pub max_retries: usize,
    pub backoff: ExponentialBackoff,
    pub always_retry: HashSet<RetryTrigger>,
    pub idempotent_retry: HashSet<RetryTrigger>,
    pub ignore_retry_after: bool,
    pub retry_response_drain_limit: usize,
    pub skip_drain_on_retry: bool,
    pub idempotency_key_header: Option<HeaderName>,
}
Expand description

Retry policy configuration with exponential backoff

Retry decisions are based on two sets of triggers:

  • always_retry: Conditions that always trigger retry (regardless of HTTP method)
  • idempotent_retry: Conditions that trigger retry only for idempotent methods (GET, HEAD, PUT, DELETE, OPTIONS, TRACE) OR when the request has an idempotency key header

Safety by default: Non-idempotent methods (POST, PATCH) are only retried on triggers in always_retry unless the request contains an idempotency key header.

Fields§

§max_retries: usize

Maximum number of retries after the initial attempt (0 = no retries, default: 3) Total attempts = 1 (initial) + max_retries

§backoff: ExponentialBackoff

Backoff strategy configuration

§always_retry: HashSet<RetryTrigger>

Triggers that always retry regardless of HTTP method Default: [Status(429)]

Note: TransportError and Timeout are NOT in always_retry by default to avoid duplicating non-idempotent requests. They are in idempotent_retry instead.

§idempotent_retry: HashSet<RetryTrigger>

Triggers that only retry for idempotent methods (GET, HEAD, OPTIONS, TRACE) OR when the request has an idempotency key header. Default: [TransportError, Timeout, Status(408), Status(500), Status(502), Status(503), Status(504)]

§ignore_retry_after: bool

If true, ignore the Retry-After HTTP header and always use backoff policy. If false (default), use Retry-After value when present for computing retry delay.

§retry_response_drain_limit: usize

Maximum bytes to drain from response body before retrying on HTTP status. Draining the body allows connection reuse. Default: 64 KiB. If the body exceeds this limit, draining stops and the connection may not be reused.

Note: This limit applies to decompressed bytes. For compressed responses, the actual network traffic may be smaller than the configured limit.

§skip_drain_on_retry: bool

Whether to skip draining response body on retry.

When true, the response body is not drained before retrying, meaning connections may not be reused after retryable errors. This saves CPU/memory by not decompressing error response bodies.

§Performance Tradeoff

Body draining operates on decompressed bytes (after DecompressionLayer). When servers return compressed error responses (e.g., gzip-compressed 503 HTML), draining requires CPU to decompress the body even though we discard the content.

Recommendation:

  • Set to true for high-throughput services where connection reuse is less important than CPU efficiency, or when error responses are typically compressed
  • Keep false (default) for low-to-medium throughput services where connection reuse reduces latency and TCP connection overhead

The Content-Length header is checked before draining; bodies larger than retry_response_drain_limit are skipped automatically regardless of this setting.

Default: false (drain enabled for connection reuse)

§idempotency_key_header: Option<HeaderName>

Header name that, when present on a request, enables retry for non-idempotent methods. Default: “Idempotency-Key”

Set to None to disable idempotency-key based retry (only always_retry triggers will apply to non-idempotent methods).

When a request includes this header, triggers in idempotent_retry will apply regardless of the HTTP method.

Pre-parsed at config construction to avoid runtime parsing overhead.

Implementations§

Source§

impl RetryConfig

Source

pub fn disabled() -> Self

Create config with no retries

Source

pub fn aggressive() -> Self

Create config with aggressive retry policy (retries all 5xx for any method)

WARNING: This policy retries non-idempotent methods on transport errors and timeouts, which may cause duplicate side effects. Use with caution.

Source

pub fn should_retry( &self, trigger: RetryTrigger, method: &Method, has_idempotency_key: bool, ) -> bool

Check if the given trigger should cause a retry for the given HTTP method

§Arguments
  • trigger - The condition that triggered the retry consideration
  • method - The HTTP method of the request
  • has_idempotency_key - Whether the request has an idempotency key header
§Retry Logic
  • Triggers in always_retry are always retried regardless of method
  • Triggers in idempotent_retry are retried if:
    • The method is idempotent (GET, HEAD, PUT, DELETE, OPTIONS, TRACE), OR
    • The request has an idempotency key header

Trait Implementations§

Source§

impl Clone for RetryConfig

Source§

fn clone(&self) -> RetryConfig

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for RetryConfig

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for RetryConfig

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> ServiceExt for T

Source§

fn decompression(self) -> Decompression<Self>
where Self: Sized,

Decompress response bodies. Read more
Source§

fn trace_for_http(self) -> Trace<Self, SharedClassifier<ServerErrorsAsFailures>>
where Self: Sized,

High level tracing that classifies responses using HTTP status codes. Read more
Source§

fn trace_for_grpc(self) -> Trace<Self, SharedClassifier<GrpcErrorsAsFailures>>
where Self: Sized,

High level tracing that classifies responses using gRPC headers. Read more
Source§

fn follow_redirects(self) -> FollowRedirect<Self>
where Self: Sized,

Follow redirect resposes using the Standard policy. Read more
Source§

fn set_request_id<M>( self, header_name: HeaderName, make_request_id: M, ) -> SetRequestId<Self, M>
where Self: Sized, M: MakeRequestId,

Add request id header and extension. Read more
Source§

fn set_x_request_id<M>(self, make_request_id: M) -> SetRequestId<Self, M>
where Self: Sized, M: MakeRequestId,

Add request id header and extension, using x-request-id as the header name. Read more
Source§

fn propagate_request_id( self, header_name: HeaderName, ) -> PropagateRequestId<Self>
where Self: Sized,

Propgate request ids from requests to responses. Read more
Source§

fn propagate_x_request_id(self) -> PropagateRequestId<Self>
where Self: Sized,

Propgate request ids from requests to responses, using x-request-id as the header name. Read more
Source§

fn request_body_limit(self, limit: usize) -> RequestBodyLimit<Self>
where Self: Sized,

Intercept requests with over-sized payloads and convert them into 413 Payload Too Large responses. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more