|
1 | | -use std::{future::Future, sync::Arc, time::Duration}; |
| 1 | +use std::{fmt::Debug, future::Future, sync::Arc, time::Duration}; |
2 | 2 |
|
3 | 3 | use alloy::{ |
4 | 4 | eips::{BlockId, BlockNumberOrTag}, |
@@ -230,44 +230,45 @@ impl<N: Network> RobustProvider<N> { |
230 | 230 | /// and all fallback providers failed" if the overall timeout elapses and no fallback |
231 | 231 | /// providers succeed. |
232 | 232 | /// - Propagates any [`RpcError<TransportErrorKind>`] from the underlying retries. |
233 | | - async fn retry_with_total_timeout<T, F, Fut>(&self, operation: F) -> Result<T, Error> |
| 233 | + async fn retry_with_total_timeout<T: Debug, F, Fut>(&self, operation: F) -> Result<T, Error> |
234 | 234 | where |
235 | 235 | F: Fn(RootProvider<N>) -> Fut, |
236 | 236 | Fut: Future<Output = Result<T, RpcError<TransportErrorKind>>>, |
237 | 237 | { |
238 | | - let mut last_error = None; |
239 | | - |
240 | | - // Try each provider in sequence (first one is primary) |
241 | | - for (idx, provider) in self.providers.iter().enumerate() { |
242 | | - if idx == 0 { |
243 | | - info!("Attempting primary provider"); |
244 | | - } else { |
245 | | - info!("Attempting fallback provider {} out of {}", idx, self.providers.len() - 1); |
246 | | - } |
| 238 | + let mut providers = self.providers.iter(); |
| 239 | + let primary = providers.next().expect("should have primary provider"); |
| 240 | + |
| 241 | + let result = self.try_provider_with_timeout(primary, &operation).await; |
| 242 | + |
| 243 | + if result.is_ok() { |
| 244 | + return result; |
| 245 | + } |
| 246 | + |
| 247 | + let mut last_error = result.unwrap_err(); |
| 248 | + |
| 249 | + if self.providers.len() > 1 { |
| 250 | + info!("Primary provider failed, trying fallback provider(s)"); |
| 251 | + } |
247 | 252 |
|
248 | | - let result = self.try_provider_with_timeout(provider, &operation).await; |
| 253 | + // This loop starts at index 1 automatically |
| 254 | + for (idx, provider) in providers.enumerate() { |
| 255 | + let fallback_num = idx + 1; |
| 256 | + info!("Attempting fallback provider {}/{}", fallback_num, self.providers.len() - 1); |
249 | 257 |
|
250 | | - match result { |
| 258 | + match self.try_provider_with_timeout(provider, &operation).await { |
251 | 259 | Ok(value) => { |
252 | | - if idx > 0 { |
253 | | - info!(provider_num = idx, "Fallback provider succeeded"); |
254 | | - } |
| 260 | + info!(provider_num = fallback_num, "Fallback provider succeeded"); |
255 | 261 | return Ok(value); |
256 | 262 | } |
257 | 263 | Err(e) => { |
258 | | - last_error = Some(e); |
259 | | - if idx == 0 && self.providers.len() > 1 { |
260 | | - info!("Primary provider failed, trying fallback provider(s)"); |
261 | | - } else { |
262 | | - error!(provider_num = idx, err = %last_error.as_ref().unwrap(), "Fallback provider failed with error"); |
263 | | - } |
| 264 | + error!(provider_num = fallback_num, err = %e, "Fallback provider failed"); |
| 265 | + last_error = e; |
264 | 266 | } |
265 | 267 | } |
266 | 268 | } |
267 | 269 |
|
268 | 270 | error!("All providers failed or timed out"); |
269 | | - // Return the last error encountered |
270 | | - Err(last_error.unwrap_or(Error::Timeout)) |
| 271 | + Err(last_error) |
271 | 272 | } |
272 | 273 |
|
273 | 274 | /// Try executing an operation with a specific provider with retry and timeout. |
|
0 commit comments