Skip to main content

ferro_queue/
error.rs

1//! Error types for the queue system.
2
3use thiserror::Error;
4
5/// Errors that can occur in the queue system.
6#[derive(Debug, Error)]
7pub enum Error {
8    /// Failed to connect to the queue backend.
9    #[error("Queue connection failed: {0}")]
10    ConnectionFailed(String),
11
12    /// Failed to serialize a job.
13    #[error("Failed to serialize job: {0}")]
14    SerializationFailed(String),
15
16    /// Failed to deserialize a job.
17    #[error("Failed to deserialize job: {0}")]
18    DeserializationFailed(String),
19
20    /// Failed to push a job to the queue.
21    #[error("Failed to push job to queue '{queue}': {message}")]
22    PushFailed {
23        /// The queue name.
24        queue: String,
25        /// The error message.
26        message: String,
27    },
28
29    /// Failed to pop a job from the queue.
30    #[error("Failed to pop job from queue '{queue}': {message}")]
31    PopFailed {
32        /// The queue name.
33        queue: String,
34        /// The error message.
35        message: String,
36    },
37
38    /// Job execution failed.
39    #[error("Job '{job}' failed: {message}")]
40    JobFailed {
41        /// The job name.
42        job: String,
43        /// The error message.
44        message: String,
45    },
46
47    /// Maximum retry attempts exceeded.
48    #[error("Job '{job}' exceeded maximum retries ({max_retries})")]
49    MaxRetriesExceeded {
50        /// The job name.
51        job: String,
52        /// Maximum retry count.
53        max_retries: u32,
54    },
55
56    /// Database error.
57    #[error("Database error: {0}")]
58    Db(#[from] sea_orm::DbErr),
59
60    /// Unsupported database backend.
61    #[error("Unsupported database backend")]
62    UnsupportedBackend,
63
64    /// JSON error.
65    #[error("JSON error: {0}")]
66    Json(#[from] serde_json::Error),
67
68    /// Tenant not found when trying to establish tenant scope for a job.
69    #[error("Tenant not found for job: tenant_id={tenant_id}")]
70    TenantNotFound {
71        /// The tenant ID that could not be resolved.
72        tenant_id: i64,
73    },
74
75    /// Custom error.
76    #[error("{0}")]
77    Custom(String),
78}
79
80impl Error {
81    /// Create a job failed error.
82    pub fn job_failed(job: impl Into<String>, message: impl Into<String>) -> Self {
83        Self::JobFailed {
84            job: job.into(),
85            message: message.into(),
86        }
87    }
88
89    /// Create a push failed error.
90    pub fn push_failed(queue: impl Into<String>, message: impl Into<String>) -> Self {
91        Self::PushFailed {
92            queue: queue.into(),
93            message: message.into(),
94        }
95    }
96
97    /// Create a tenant not found error.
98    pub fn tenant_not_found(id: i64) -> Self {
99        Self::TenantNotFound { tenant_id: id }
100    }
101
102    /// Create a custom error.
103    pub fn custom(message: impl Into<String>) -> Self {
104        Self::Custom(message.into())
105    }
106}
107
108impl From<String> for Error {
109    fn from(s: String) -> Self {
110        Self::Custom(s)
111    }
112}
113
114impl From<&str> for Error {
115    fn from(s: &str) -> Self {
116        Self::Custom(s.to_string())
117    }
118}
119
120#[cfg(test)]
121mod tests {
122    use super::*;
123
124    #[test]
125    fn test_tenant_not_found_formats_with_id() {
126        let err = Error::tenant_not_found(42);
127        assert_eq!(err.to_string(), "Tenant not found for job: tenant_id=42");
128    }
129
130    #[test]
131    fn test_tenant_not_found_constructor() {
132        let err = Error::tenant_not_found(99);
133        assert!(matches!(err, Error::TenantNotFound { tenant_id: 99 }));
134    }
135}