use crate::core::error::YfError;
const MAX_RETRIES: u32 = 100;
#[derive(Clone, Debug)]
pub enum Backoff {
Fixed(std::time::Duration),
Exponential {
base: std::time::Duration,
factor: f64,
max: std::time::Duration,
jitter: bool,
},
}
impl Backoff {
pub fn validate(&self) -> Result<(), YfError> {
match self {
Self::Exponential { factor, .. } if !factor.is_finite() || *factor <= 0.0 => {
Err(YfError::InvalidParams(
"retry exponential backoff factor must be finite and greater than zero".into(),
))
}
Self::Fixed(_) | Self::Exponential { .. } => Ok(()),
}
}
}
#[derive(Clone, Debug)]
pub struct RetryConfig {
pub enabled: bool,
pub max_retries: u32,
pub backoff: Backoff,
pub retry_on_status: Vec<u16>,
pub retry_on_timeout: bool,
pub retry_on_connect: bool,
}
impl RetryConfig {
pub const MAX_RETRIES: u32 = MAX_RETRIES;
pub fn validate(&self) -> Result<(), YfError> {
if !self.enabled {
return Ok(());
}
if self.max_retries > Self::MAX_RETRIES {
return Err(YfError::InvalidParams(format!(
"retry max_retries cannot exceed {}",
Self::MAX_RETRIES
)));
}
self.backoff.validate()
}
}
impl Default for RetryConfig {
fn default() -> Self {
Self {
enabled: true,
max_retries: 4,
backoff: Backoff::Exponential {
base: std::time::Duration::from_millis(200),
factor: 2.0,
max: std::time::Duration::from_secs(3),
jitter: true,
},
retry_on_status: vec![408, 429, 500, 502, 503, 504],
retry_on_timeout: true,
retry_on_connect: true,
}
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum CacheMode {
#[default]
Default,
Use,
Refresh,
Bypass,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum CacheEndpoint {
Quote,
Chart,
QuoteSummary,
Fundamentals,
Options,
News,
Search,
Screener,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum EffectiveCacheMode {
Use,
Refresh,
Bypass,
}
impl CacheEndpoint {
const fn default_mode(self) -> EffectiveCacheMode {
match self {
Self::Quote | Self::Options | Self::News | Self::Screener => EffectiveCacheMode::Bypass,
Self::Chart | Self::QuoteSummary | Self::Fundamentals | Self::Search => {
EffectiveCacheMode::Use
}
}
}
}
impl CacheMode {
const fn effective(self, endpoint: CacheEndpoint) -> EffectiveCacheMode {
match self {
Self::Default => endpoint.default_mode(),
Self::Use => EffectiveCacheMode::Use,
Self::Refresh => EffectiveCacheMode::Refresh,
Self::Bypass => EffectiveCacheMode::Bypass,
}
}
pub(crate) const fn reads(self, endpoint: CacheEndpoint) -> bool {
matches!(self.effective(endpoint), EffectiveCacheMode::Use)
}
pub(crate) const fn writes(self, endpoint: CacheEndpoint) -> bool {
matches!(
self.effective(endpoint),
EffectiveCacheMode::Use | EffectiveCacheMode::Refresh
)
}
}