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.
This commit is contained in:
Luke Parker 2023-11-07 22:51:02 -05:00
parent 56fd11ab8d
commit e1c07d89e0
No known key found for this signature in database

View file

@ -185,25 +185,34 @@ impl HttpRpc {
if response_result.is_err() { if response_result.is_err() {
connection_lock.0 = None; 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, // If we're not already recursing and:
// unless we're already recursing // 1) We had a connection error
if (!recursing) && (response.status() == StatusCode::UNAUTHORIZED) { // 2) We need to re-auth due to this token being stale
if let Some(header) = response.headers().get("www-authenticate") { // recursively re-call this function
if header if (!recursing) &&
.to_str() (response_result.is_err() || {
.map_err(|_| RpcError::InvalidNode("www-authenticate header wasn't a string"))? let response = response_result.as_ref().unwrap();
.contains("stale") if response.status() == StatusCode::UNAUTHORIZED {
{ if let Some(header) = response.headers().get("www-authenticate") {
connection_lock.0 = None; header
drop(connection_lock); .to_str()
return self.inner_post(route, body, true).await; .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?
} }
}; };