use std::time::Duration;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct RetryContext {
attempt: u32,
max_attempts: u32,
max_operation_elapsed: Option<Duration>,
max_total_elapsed: Option<Duration>,
operation_elapsed: Duration,
total_elapsed: Duration,
attempt_elapsed: Duration,
attempt_timeout: Option<Duration>,
next_delay: Option<Duration>,
retry_after_hint: Option<Duration>,
attempt_timeout_source: Option<AttemptTimeoutSource>,
unreaped_worker_count: u32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum AttemptTimeoutSource {
Configured,
MaxOperationElapsed,
MaxTotalElapsed,
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct RetryContextParts {
pub(crate) attempt: u32,
pub(crate) max_attempts: u32,
pub(crate) max_operation_elapsed: Option<Duration>,
pub(crate) max_total_elapsed: Option<Duration>,
pub(crate) operation_elapsed: Duration,
pub(crate) total_elapsed: Duration,
pub(crate) attempt_elapsed: Duration,
pub(crate) attempt_timeout: Option<Duration>,
}
impl RetryContext {
pub fn new(attempt: u32, max_attempts: u32) -> Self {
Self::from_parts(RetryContextParts {
attempt,
max_attempts,
max_operation_elapsed: None,
max_total_elapsed: None,
operation_elapsed: Duration::ZERO,
total_elapsed: Duration::ZERO,
attempt_elapsed: Duration::ZERO,
attempt_timeout: None,
})
}
pub(crate) fn from_parts(parts: RetryContextParts) -> Self {
Self {
attempt: parts.attempt,
max_attempts: parts.max_attempts,
max_operation_elapsed: parts.max_operation_elapsed,
max_total_elapsed: parts.max_total_elapsed,
operation_elapsed: parts.operation_elapsed,
total_elapsed: parts.total_elapsed,
attempt_elapsed: parts.attempt_elapsed,
attempt_timeout: parts.attempt_timeout,
next_delay: None,
retry_after_hint: None,
attempt_timeout_source: None,
unreaped_worker_count: 0,
}
}
#[inline]
pub fn attempt(&self) -> u32 {
self.attempt
}
#[inline]
pub fn max_attempts(&self) -> u32 {
self.max_attempts
}
#[inline]
pub fn max_retries(&self) -> u32 {
self.max_attempts.saturating_sub(1)
}
#[inline]
pub fn max_operation_elapsed(&self) -> Option<Duration> {
self.max_operation_elapsed
}
#[inline]
pub fn max_total_elapsed(&self) -> Option<Duration> {
self.max_total_elapsed
}
#[inline]
pub fn operation_elapsed(&self) -> Duration {
self.operation_elapsed
}
#[inline]
pub fn total_elapsed(&self) -> Duration {
self.total_elapsed
}
#[inline]
pub fn attempt_elapsed(&self) -> Duration {
self.attempt_elapsed
}
#[inline]
pub fn attempt_timeout(&self) -> Option<Duration> {
self.attempt_timeout
}
#[inline]
pub fn attempt_timeout_source(&self) -> Option<AttemptTimeoutSource> {
self.attempt_timeout_source
}
#[inline]
pub fn unreaped_worker_count(&self) -> u32 {
self.unreaped_worker_count
}
#[inline]
pub fn next_delay(&self) -> Option<Duration> {
self.next_delay
}
#[inline]
pub fn retry_after_hint(&self) -> Option<Duration> {
self.retry_after_hint
}
#[inline]
pub(crate) fn with_next_delay(mut self, delay: Duration) -> Self {
self.next_delay = Some(delay);
self
}
#[inline]
pub(crate) fn with_total_elapsed(mut self, total_elapsed: Duration) -> Self {
self.total_elapsed = total_elapsed;
self
}
#[inline]
pub(crate) fn with_retry_after_hint(mut self, hint: Option<Duration>) -> Self {
self.retry_after_hint = hint;
self
}
#[inline]
pub(crate) fn with_attempt_timeout_source(
mut self,
source: Option<AttemptTimeoutSource>,
) -> Self {
if let Some(source) = source {
self.attempt_timeout_source = Some(source);
}
self
}
#[inline]
pub(crate) fn with_unreaped_worker_count(mut self, count: u32) -> Self {
self.unreaped_worker_count = count;
self
}
}