From 1efb0443ccc1bc0ebc1458255e82528954af8818 Mon Sep 17 00:00:00 2001 From: Victor Kirov Date: Sun, 23 Jul 2023 15:28:35 +0300 Subject: [PATCH] Add retry to fetcher (#2297) --- src/index/fetcher.rs | 65 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 53 insertions(+), 12 deletions(-) diff --git a/src/index/fetcher.rs b/src/index/fetcher.rs index baf31064aa..774405b9f5 100644 --- a/src/index/fetcher.rs +++ b/src/index/fetcher.rs @@ -65,23 +65,38 @@ impl Fetcher { } let body = Value::Array(reqs).to_string(); - let req = Request::builder() - .method(Method::POST) - .uri(&self.url) - .header(hyper::header::AUTHORIZATION, &self.auth) - .header(hyper::header::CONTENT_TYPE, "application/json") - .body(Body::from(body))?; - let response = self.client.request(req).await?; - - let buf = hyper::body::to_bytes(response).await?; - - let mut results: Vec> = serde_json::from_slice(&buf)?; + let mut results: Vec>; + let mut retries = 0; + + loop { + results = match self.try_get_transactions(body.clone()).await { + Ok(results) => results, + Err(error) => { + if retries >= 5 { + return Err(anyhow!( + "failed to fetch raw transactions after 5 retries: {}", + error + )); + } + + log::info!("failed to fetch raw transactions, retrying: {}", error); + + tokio::time::sleep(tokio::time::Duration::from_millis( + 100 * u64::pow(2, retries), + )) + .await; + retries += 1; + continue; + } + }; + break; + } // Return early on any error, because we need all results to proceed if let Some(err) = results.iter().find_map(|res| res.error.as_ref()) { return Err(anyhow!( - "Failed to fetch raw transaction: code {} message {}", + "failed to fetch raw transaction: code {} message {}", err.code, err.message )); @@ -109,4 +124,30 @@ impl Fetcher { .collect::>>()?; Ok(txs) } + + async fn try_get_transactions(&self, body: String) -> Result>> { + let req = Request::builder() + .method(Method::POST) + .uri(&self.url) + .header(hyper::header::AUTHORIZATION, &self.auth) + .header(hyper::header::CONTENT_TYPE, "application/json") + .body(Body::from(body))?; + + let response = self.client.request(req).await?; + + let buf = hyper::body::to_bytes(response).await?; + + let results: Vec> = match serde_json::from_slice(&buf) { + Ok(results) => results, + Err(e) => { + return Err(anyhow!( + "failed to parse JSON-RPC response: {e}. response: {response}", + e = e, + response = String::from_utf8_lossy(&buf) + )) + } + }; + + Ok(results) + } }