use std::pin::Pin; use futures::{Future, FutureExt}; use tower::retry::Policy; /// A very basic retry policy with a limited number of retry attempts. /// /// XXX Remove this when https://github.com/tower-rs/tower/pull/414 lands. #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub struct RetryLimit { remaining_tries: usize, } impl RetryLimit { /// Create a policy with the given number of retry attempts. pub fn new(retry_attempts: usize) -> Self { RetryLimit { remaining_tries: retry_attempts, } } } impl Policy for RetryLimit { type Future = Pin + Send + Sync + 'static>>; fn retry(&self, req: &Req, result: Result<&Res, &E>) -> Option { if let Err(e) = result { if self.remaining_tries > 0 { tracing::debug!(?req, ?e, remaining_tries = self.remaining_tries, "retrying"); let remaining_tries = self.remaining_tries - 1; let retry_outcome = RetryLimit { remaining_tries }; Some( // Let other tasks run, so we're more likely to choose a different peer, // and so that any notfound inv entries win the race to the PeerSet. // // TODO: move syncer retries into the PeerSet, // so we always choose different peers (#3235) Box::pin(tokio::task::yield_now().map(move |()| retry_outcome)), ) } else { None } } else { None } } fn clone_request(&self, req: &Req) -> Option { Some(req.clone()) } }