cala_server/job/
traits.rs

1use async_trait::async_trait;
2use chrono::{DateTime, Utc};
3
4use super::{
5    current::CurrentJob,
6    entity::{Job, JobType},
7};
8use cala_ledger::CalaLedger;
9
10pub trait JobInitializer: Send + Sync + 'static {
11    fn job_type() -> JobType
12    where
13        Self: Sized;
14
15    fn retry_on_error_settings() -> RetrySettings
16    where
17        Self: Sized,
18    {
19        Default::default()
20    }
21
22    fn init(
23        &self,
24        job: Job,
25        ledger: &CalaLedger,
26    ) -> Result<Box<dyn JobRunner>, Box<dyn std::error::Error>>;
27}
28
29pub enum JobCompletion {
30    Complete,
31    CompleteWithTx(sqlx::Transaction<'static, sqlx::Postgres>),
32    RescheduleAt(DateTime<Utc>),
33    RescheduleAtWithTx(sqlx::Transaction<'static, sqlx::Postgres>, DateTime<Utc>),
34}
35
36#[async_trait]
37pub trait JobRunner: Send + Sync + 'static {
38    async fn run(
39        &self,
40        current_job: CurrentJob,
41    ) -> Result<JobCompletion, Box<dyn std::error::Error>>;
42}
43
44pub struct RetrySettings {
45    pub n_attempts: u32,
46    pub min_backoff: std::time::Duration,
47    pub max_backoff: std::time::Duration,
48}
49
50impl RetrySettings {
51    pub(super) fn next_attempt_at(&self, attempt: u32) -> DateTime<Utc> {
52        let backoff = std::cmp::min(
53            self.min_backoff.as_secs() * 2u64.pow(attempt - 1),
54            self.max_backoff.as_secs(),
55        );
56        chrono::Utc::now() + std::time::Duration::from_secs(backoff)
57    }
58}
59
60impl Default for RetrySettings {
61    fn default() -> Self {
62        Self {
63            n_attempts: 10,
64            min_backoff: std::time::Duration::from_secs(1),
65            max_backoff: std::time::Duration::from_secs(60),
66        }
67    }
68}