use crate::error::LlmError;
use crate::types::ProviderType;
pub use crate::retry::RetryPolicy;
pub use crate::retry_backoff::BackoffRetryExecutor;
#[allow(deprecated)]
pub use crate::retry_strategy::{FailoverConfig, FailoverManager, RateLimitConfig, RetryStrategy};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RetryBackend {
Backoff,
Policy,
Strategy,
}
impl Default for RetryBackend {
fn default() -> Self {
Self::Backoff
}
}
#[allow(deprecated)]
#[derive(Debug, Clone)]
pub struct RetryOptions {
pub backend: RetryBackend,
pub provider: Option<ProviderType>,
pub policy: Option<RetryPolicy>,
pub strategy: Option<RetryStrategy>,
pub rate_limit: Option<RateLimitConfig>,
}
impl Default for RetryOptions {
fn default() -> Self {
Self {
backend: RetryBackend::Backoff,
provider: None,
policy: None,
strategy: None,
rate_limit: None,
}
}
}
#[allow(deprecated)]
impl RetryOptions {
pub fn backoff() -> Self {
Self::default()
}
pub fn backoff_for_provider(provider: ProviderType) -> Self {
Self {
backend: RetryBackend::Backoff,
provider: Some(provider),
..Default::default()
}
}
pub fn policy_default() -> Self {
Self {
backend: RetryBackend::Policy,
policy: Some(crate::retry::RetryPolicy::default()),
..Default::default()
}
}
pub fn with_max_attempts(mut self, attempts: u32) -> Self {
if let Some(policy) = self.policy.take() {
self.policy = Some(policy.with_max_attempts(attempts));
}
self
}
pub fn with_strategy(strategy: RetryStrategy) -> Self {
Self {
backend: RetryBackend::Strategy,
strategy: Some(strategy),
..Default::default()
}
}
pub fn with_rate_limit(mut self, cfg: RateLimitConfig) -> Self {
self.rate_limit = Some(cfg);
self
}
}
pub async fn retry<F, Fut, T>(operation: F) -> Result<T, LlmError>
where
F: Fn() -> Fut + Send + Sync,
Fut: std::future::Future<Output = Result<T, LlmError>> + Send,
T: Send,
{
crate::retry_backoff::retry_with_backoff(operation).await
}
pub async fn retry_for_provider<F, Fut, T>(
provider: &ProviderType,
operation: F,
) -> Result<T, LlmError>
where
F: Fn() -> Fut + Send + Sync,
Fut: std::future::Future<Output = Result<T, LlmError>> + Send,
T: Send,
{
crate::retry_backoff::retry_for_provider_backoff(provider, operation).await
}
#[allow(deprecated)]
pub async fn retry_with<F, Fut, T>(operation: F, options: RetryOptions) -> Result<T, LlmError>
where
F: Fn() -> Fut + Send + Sync,
Fut: std::future::Future<Output = Result<T, LlmError>> + Send,
T: Send,
{
match options.backend {
RetryBackend::Backoff => {
if let Some(provider) = options.provider.as_ref() {
crate::retry_backoff::retry_for_provider_backoff(provider, operation).await
} else {
crate::retry_backoff::retry_with_backoff(operation).await
}
}
RetryBackend::Policy => {
let policy = options.policy.unwrap_or_default();
let executor = crate::retry::RetryExecutor::new(policy);
executor.execute(operation).await
}
RetryBackend::Strategy => {
let mut executor =
crate::retry_strategy::RetryExecutor::new(options.strategy.unwrap_or_default());
if let Some(cfg) = options.rate_limit {
executor = executor.with_rate_limit_handler(cfg);
}
executor.execute(operation).await
}
}
}