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() {
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?
}
};