From 281dfa718876bcd73caa967f26a03dfee0772567 Mon Sep 17 00:00:00 2001 From: Haitao Huang Date: Mon, 9 Feb 2026 23:52:18 +0000 Subject: [PATCH] tools/migtd-collateral-generator: add retry for intel collaterals Add exponential backoff retry logic to PCS HTTP requests. Transient failures (5xx, 429 and 408) are retried with doubling delays starting at 10 seconds up to a maximum of 180 seconds. Network and connection errors are also retried since they propagate as errors from reqwest. Signed-off-by: Haitao Huang --- .../src/pcs_client.rs | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/tools/migtd-collateral-generator/src/pcs_client.rs b/tools/migtd-collateral-generator/src/pcs_client.rs index faa00959..ba171280 100644 --- a/tools/migtd-collateral-generator/src/pcs_client.rs +++ b/tools/migtd-collateral-generator/src/pcs_client.rs @@ -202,11 +202,49 @@ fn remove_header_case_insensitive( actual_key.and_then(|key| headers.remove(&key)) } +/// Initial retry delay in seconds after a transient failure. +const INITIAL_RETRY_DELAY_SECS: u64 = 10; +/// Maximum retry delay in seconds. Once the next delay would exceed this, error out. +const MAX_RETRY_DELAY_SECS: u64 = 180; + pub async fn fetch_data_from_url(url: &str) -> Result { let client = Client::new(); + + let mut delay = std::time::Duration::from_secs(INITIAL_RETRY_DELAY_SECS); + let max_delay = std::time::Duration::from_secs(MAX_RETRY_DELAY_SECS); + loop { + match send_request(&client, url).await { + Ok(response) => return Ok(response), + Err(e) => { + if delay > max_delay { + eprintln!("Request to {} failed after retries: {}", url, e); + return Err(e); + } + eprintln!( + "Request to {} failed: {}. Retrying in {} seconds...", + url, + e, + delay.as_secs() + ); + tokio::time::sleep(delay).await; + delay *= 2; + } + } + } +} + +async fn send_request(client: &Client, url: &str) -> Result { let response = client.get(url).send().await?; let status = response.status().as_u16() as u32; + // Treat server errors (5xx), 429 (Too Many Requests) and 408 (Request + // Timeout) as transient failures so the retry loop in fetch_data_from_url + // will back off and try again. Network/connection errors are already + // transient because they propagate as Err from reqwest. + if (500..600).contains(&status) || status == 429 || status == 408 { + return Err(anyhow!("Transient HTTP error {} from {}", status, url)); + } + let mut header_map = HashMap::new(); for (key, value) in response.headers() { header_map.insert(