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: usizeMaximum number of retries after the initial attempt (0 = no retries, default: 3)
Total attempts = 1 (initial) + max_retries
backoff: ExponentialBackoffBackoff 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: boolIf 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: usizeMaximum 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: boolWhether 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
truefor 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
impl RetryConfig
Sourcepub fn aggressive() -> Self
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.
Sourcepub fn should_retry(
&self,
trigger: RetryTrigger,
method: &Method,
has_idempotency_key: bool,
) -> bool
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 considerationmethod- The HTTP method of the requesthas_idempotency_key- Whether the request has an idempotency key header
§Retry Logic
- Triggers in
always_retryare always retried regardless of method - Triggers in
idempotent_retryare 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
impl Clone for RetryConfig
Source§fn clone(&self) -> RetryConfig
fn clone(&self) -> RetryConfig
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for RetryConfig
impl Debug for RetryConfig
Auto Trait Implementations§
impl !Freeze for RetryConfig
impl RefUnwindSafe for RetryConfig
impl Send for RetryConfig
impl Sync for RetryConfig
impl Unpin for RetryConfig
impl UnwindSafe for RetryConfig
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
Source§impl<T> ServiceExt for T
impl<T> ServiceExt for T
Source§fn decompression(self) -> Decompression<Self>where
Self: Sized,
fn decompression(self) -> Decompression<Self>where
Self: Sized,
Source§fn trace_for_http(self) -> Trace<Self, SharedClassifier<ServerErrorsAsFailures>>where
Self: Sized,
fn trace_for_http(self) -> Trace<Self, SharedClassifier<ServerErrorsAsFailures>>where
Self: Sized,
Source§fn trace_for_grpc(self) -> Trace<Self, SharedClassifier<GrpcErrorsAsFailures>>where
Self: Sized,
fn trace_for_grpc(self) -> Trace<Self, SharedClassifier<GrpcErrorsAsFailures>>where
Self: Sized,
Source§fn follow_redirects(self) -> FollowRedirect<Self>where
Self: Sized,
fn follow_redirects(self) -> FollowRedirect<Self>where
Self: Sized,
Source§fn set_request_id<M>(
self,
header_name: HeaderName,
make_request_id: M,
) -> SetRequestId<Self, M>where
Self: Sized,
M: MakeRequestId,
fn set_request_id<M>(
self,
header_name: HeaderName,
make_request_id: M,
) -> SetRequestId<Self, M>where
Self: Sized,
M: MakeRequestId,
Source§fn set_x_request_id<M>(self, make_request_id: M) -> SetRequestId<Self, M>where
Self: Sized,
M: MakeRequestId,
fn set_x_request_id<M>(self, make_request_id: M) -> SetRequestId<Self, M>where
Self: Sized,
M: MakeRequestId,
x-request-id as the header name. Read moreSource§fn propagate_request_id(
self,
header_name: HeaderName,
) -> PropagateRequestId<Self>where
Self: Sized,
fn propagate_request_id(
self,
header_name: HeaderName,
) -> PropagateRequestId<Self>where
Self: Sized,
Source§fn propagate_x_request_id(self) -> PropagateRequestId<Self>where
Self: Sized,
fn propagate_x_request_id(self) -> PropagateRequestId<Self>where
Self: Sized,
x-request-id as the header name. Read moreSource§fn request_body_limit(self, limit: usize) -> RequestBodyLimit<Self>where
Self: Sized,
fn request_body_limit(self, limit: usize) -> RequestBodyLimit<Self>where
Self: Sized,
413 Payload Too Large responses. Read more