MCPcopy Index your code
hub / github.com/AI45Lab/Code / with_retry

Function with_retry

core/src/retry.rs:131–184  ·  view source on GitHub ↗

Execute an async operation with retry logic. The `operation` closure is called on each attempt and must return an `AttemptOutcome`. On retryable failures, waits with exponential backoff before retrying. On fatal failures or after exhausting retries, returns an error.

(config: &RetryConfig, operation: F)

Source from the content-addressed store, hash-verified

129/// On retryable failures, waits with exponential backoff before retrying.
130/// On fatal failures or after exhausting retries, returns an error.
131pub async fn with_retry<T, F, Fut>(config: &RetryConfig, operation: F) -> anyhow::Result<T>
132where
133 F: Fn(u32) -> Fut,
134 Fut: std::future::Future<Output = AttemptOutcome<T>>,
135{
136 let mut last_status = None;
137 let mut last_body = String::new();
138
139 for attempt in 0..=config.max_retries {
140 match operation(attempt).await {
141 AttemptOutcome::Success(value) => {
142 if attempt > 0 {
143 tracing::info!("LLM API request succeeded after {} retries", attempt);
144 }
145 return Ok(value);
146 }
147 AttemptOutcome::Fatal(err) => {
148 return Err(err);
149 }
150 AttemptOutcome::Retryable {
151 status,
152 body,
153 retry_after,
154 } => {
155 last_status = Some(status);
156 last_body = body;
157
158 if attempt < config.max_retries {
159 // Determine delay: prefer Retry-After header, fallback to exponential backoff
160 let delay = retry_after.unwrap_or_else(|| config.delay_for_attempt(attempt));
161
162 tracing::warn!(
163 "LLM API request failed with {} (attempt {}/{}), retrying in {:?}",
164 status,
165 attempt + 1,
166 config.max_retries + 1,
167 delay,
168 );
169
170 tokio::time::sleep(delay).await;
171 }
172 }
173 }
174 }
175
176 // All retries exhausted
177 let status = last_status.unwrap_or(StatusCode::INTERNAL_SERVER_ERROR);
178 anyhow::bail!(
179 "LLM API request failed after {} attempts. Last status: {} Body: {}",
180 config.max_retries + 1,
181 status,
182 last_body,
183 )
184}
185
186/// Heuristic: is this a transient *network* error worth retrying — a timeout,
187/// connection reset/refused/closed, broken pipe, DNS failure, or a request that

Calls 1

delay_for_attemptMethod · 0.80