use std::{any::Any, sync::Arc};
use crate::job::Job;
pub struct Permit {
_permit: std::sync::Arc<dyn Any + Send + Sync>,
}
impl Permit {
pub fn new<T: Any + Send + Sync>(value: T) -> Self {
Self {
_permit: Arc::new(value),
}
}
}
#[derive(Debug)]
pub enum JobStrategyError {
CancelJob,
TryAfter(chrono::Duration),
Retry,
MarkCompleted,
}
pub trait JobStrategy: Send + Sync {
fn acquire(&self, job: &Job)
-> crate::handler::BoxFuture<'_, Result<Permit, JobStrategyError>>;
}
pub struct InstantStrategy {}
impl JobStrategy for InstantStrategy {
fn acquire(
&self,
_job: &Job,
) -> crate::handler::BoxFuture<'_, Result<Permit, JobStrategyError>> {
Box::pin(async move { Ok(Permit::new(())) })
}
}
#[derive(Clone)]
pub enum BackoffStrategy {
Linear {
delay: chrono::Duration,
},
Exponential {
factor: f64,
max_delay: chrono::Duration,
},
Custom(fn(i32) -> chrono::Duration),
}
impl Default for BackoffStrategy {
fn default() -> Self {
Self::Linear {
delay: chrono::Duration::seconds(5),
}
}
}
impl BackoffStrategy {
#[tracing::instrument(skip_all,fields(job_id=%job.id))]
pub fn next_attempt(&self, job: &Job) -> chrono::DateTime<chrono::Utc> {
match self {
BackoffStrategy::Linear { delay } => chrono::Utc::now() + *delay,
BackoffStrategy::Exponential { factor, max_delay } => {
let delay = chrono::Duration::seconds((job.attempt as f64).powf(*factor) as i64);
chrono::Utc::now() + delay.min(*max_delay)
}
BackoffStrategy::Custom(f) => chrono::Utc::now() + f(job.attempt),
}
}
}