From e1c07d89e0044210cbec9c14f39500b7d95d29fe Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Tue, 7 Nov 2023 22:51:02 -0500 Subject: [PATCH] Retry RPC requests once on error I don't like blindly retrying in the Monero library. The amount of errors, which weren't present with reqwest (well, the error rate was the same, yet due to a distinct bug this code fixed), demand we do *something* though. The trace log shows hyper is erroring with 0 bytes of the response read. My guess is it's somehow a closed connection? A connection pool would detect this and have created a new connection (as this does, except once finding out there's an issue). While we should be able to detect this with `ready()`, we do call ready and it claims no error. We also can successfully write which makes this... a mess. Hopefully, it either actually works as intended, yet it at least requires two consecutive errors which should be much less frequent. --- coins/monero/src/rpc/http.rs | 39 ++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/coins/monero/src/rpc/http.rs b/coins/monero/src/rpc/http.rs index 402d17a5..bcf201c9 100644 --- a/coins/monero/src/rpc/http.rs +++ b/coins/monero/src/rpc/http.rs @@ -185,25 +185,34 @@ impl HttpRpc { if response_result.is_err() { connection_lock.0 = None; } - let response = response_result?; - // If we need to re-auth due to this token being stale, recursively re-call this function, - // unless we're already recursing - if (!recursing) && (response.status() == StatusCode::UNAUTHORIZED) { - if let Some(header) = response.headers().get("www-authenticate") { - if header - .to_str() - .map_err(|_| RpcError::InvalidNode("www-authenticate header wasn't a string"))? - .contains("stale") - { - connection_lock.0 = None; - drop(connection_lock); - return self.inner_post(route, body, true).await; + // If we're not already recursing and: + // 1) We had a connection error + // 2) We need to re-auth due to this token being stale + // recursively re-call this function + if (!recursing) && + (response_result.is_err() || { + let response = response_result.as_ref().unwrap(); + if response.status() == StatusCode::UNAUTHORIZED { + if let Some(header) = response.headers().get("www-authenticate") { + header + .to_str() + .map_err(|_| RpcError::InvalidNode("www-authenticate header wasn't a string"))? + .contains("stale") + } else { + false + } + } else { + false } - } + }) + { + connection_lock.0 = None; + drop(connection_lock); + return self.inner_post(route, body, true).await; } - response + response_result? } };