Skip to main content

runledger_runtime/
error.rs

1use thiserror::Error;
2
3pub type Result<T> = std::result::Result<T, Error>;
4
5#[derive(Debug, Error)]
6pub enum Error {
7    #[error(transparent)]
8    Scheduler(#[from] SchedulerError),
9    #[error(transparent)]
10    Worker(#[from] WorkerError),
11    #[error(transparent)]
12    Reaper(#[from] ReaperError),
13    #[error(transparent)]
14    Runtime(#[from] RuntimeError),
15}
16
17#[derive(Debug, Error)]
18pub enum SchedulerError {
19    #[error("failed to begin scheduler transaction")]
20    BeginTransaction { source: runledger_postgres::Error },
21    #[error("failed to commit scheduler transaction")]
22    CommitTransaction { source: runledger_postgres::Error },
23    #[error("failed to claim due schedules")]
24    ClaimDueSchedules { source: runledger_postgres::Error },
25    #[error("failed to create savepoint using `{statement}`")]
26    SavepointCreate {
27        statement: &'static str,
28        source: runledger_postgres::Error,
29    },
30    #[error("failed to rollback savepoint using `{statement}`")]
31    SavepointRollback {
32        statement: &'static str,
33        source: runledger_postgres::Error,
34    },
35    #[error("failed to release savepoint using `{statement}`")]
36    SavepointRelease {
37        statement: &'static str,
38        source: runledger_postgres::Error,
39    },
40    #[error("failed deferring failed schedule `{schedule_id}`")]
41    DeferFailedSchedule {
42        schedule_id: uuid::Uuid,
43        source: runledger_postgres::Error,
44    },
45    #[error(
46        "invalid cron expression for schedule `{schedule_name}` ({schedule_id}): `{cron_expr}`"
47    )]
48    InvalidCronExpression {
49        schedule_id: uuid::Uuid,
50        schedule_name: String,
51        cron_expr: String,
52    },
53    #[error("failed enqueueing scheduled job `{job_type}` from schedule `{schedule_id}`")]
54    EnqueueScheduledJob {
55        schedule_id: uuid::Uuid,
56        job_type: String,
57        source: runledger_postgres::Error,
58    },
59    #[error("failed marking schedule `{schedule_id}` as fired")]
60    MarkScheduleFired {
61        schedule_id: uuid::Uuid,
62        source: runledger_postgres::Error,
63    },
64}
65
66#[derive(Debug, Error)]
67pub enum WorkerError {
68    #[error("failed claiming jobs for worker `{worker_id}`")]
69    ClaimJobs {
70        worker_id: String,
71        source: runledger_postgres::Error,
72    },
73    #[error("failed setting running progress for job `{job_id}` attempt `{attempt}`")]
74    SetRunningProgress {
75        job_id: uuid::Uuid,
76        attempt: i32,
77        source: runledger_postgres::Error,
78    },
79    #[error("failed releasing unstarted claim for job `{job_id}` attempt `{attempt}`")]
80    ReleaseUnstartedClaim {
81        job_id: uuid::Uuid,
82        attempt: i32,
83        source: runledger_postgres::Error,
84    },
85    #[error("failed completing job `{job_id}` attempt `{attempt}` as success")]
86    CompleteSuccess {
87        job_id: uuid::Uuid,
88        attempt: i32,
89        source: runledger_postgres::Error,
90    },
91    #[error("failed completing job `{job_id}` attempt `{attempt}` as failure")]
92    CompleteFailure {
93        job_id: uuid::Uuid,
94        attempt: i32,
95        source: runledger_postgres::Error,
96    },
97    #[error("failed heartbeat for job `{job_id}` attempt `{attempt}`")]
98    Heartbeat {
99        job_id: uuid::Uuid,
100        attempt: i32,
101        source: runledger_postgres::Error,
102    },
103}
104
105#[derive(Debug, Error)]
106pub enum ReaperError {
107    #[error(
108        "failed reaping expired leases with batch_size `{batch_size}` and retry_delay_ms `{retry_delay_ms}`"
109    )]
110    ReapExpiredLeases {
111        batch_size: i64,
112        retry_delay_ms: i32,
113        source: runledger_postgres::Error,
114    },
115}
116
117#[derive(Debug, Error)]
118pub enum RuntimeError {
119    #[error("jobs runtime task `{task}` exited unexpectedly before shutdown")]
120    TaskExitedUnexpectedly { task: &'static str },
121    #[error("failed joining jobs runtime task `{task}`")]
122    TaskJoin {
123        task: &'static str,
124        #[source]
125        source: tokio::task::JoinError,
126    },
127}
128
129#[cfg(test)]
130mod tests {
131    use super::*;
132
133    #[test]
134    fn scheduler_invalid_cron_variant_contains_schedule_metadata() {
135        let schedule_id = uuid::Uuid::nil();
136        let error = SchedulerError::InvalidCronExpression {
137            schedule_id,
138            schedule_name: "nightly sync".to_string(),
139            cron_expr: "not cron".to_string(),
140        };
141
142        match error {
143            SchedulerError::InvalidCronExpression {
144                schedule_id: actual_id,
145                schedule_name,
146                cron_expr,
147            } => {
148                assert_eq!(actual_id, schedule_id);
149                assert_eq!(schedule_name, "nightly sync");
150                assert_eq!(cron_expr, "not cron");
151            }
152            other => panic!("expected invalid cron variant, got: {other:?}"),
153        }
154    }
155}