use std::time::Duration;
use async_io::Timer;
use crate::error::{Error, ErrorKind};
use crate::request::Method;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum RetryPolicy {
None,
Limit(usize),
}
impl Default for RetryPolicy {
fn default() -> Self {
Self::None
}
}
pub(crate) fn retry_attempts(policy: RetryPolicy) -> usize {
match policy {
RetryPolicy::None => 0,
RetryPolicy::Limit(limit) => limit,
}
}
pub(crate) fn is_idempotent_method(method: Method) -> bool {
matches!(
method,
Method::Get | Method::Head | Method::Options | Method::Trace
)
}
pub(crate) fn should_retry_stale_connection(method: Method, err: &Error) -> bool {
is_idempotent_method(method) && err.kind() == &ErrorKind::StaleConnection
}
pub(crate) fn should_retry_request(method: Method, err: &Error, remaining_attempts: usize) -> bool {
remaining_attempts > 0
&& is_idempotent_method(method)
&& matches!(err.kind(), ErrorKind::Transport | ErrorKind::Timeout)
}
pub(crate) async fn backoff(attempt_index: usize) {
const BASE_MS: u64 = 100;
const CAP_MS: u64 = 5_000;
let ms = (BASE_MS * (1u64 << attempt_index)).min(CAP_MS);
Timer::after(Duration::from_millis(ms)).await;
}