use thiserror::Error;
#[derive(Debug, Error)]
pub enum Error {
#[error("Queue connection failed: {0}")]
ConnectionFailed(String),
#[error("Failed to serialize job: {0}")]
SerializationFailed(String),
#[error("Failed to deserialize job: {0}")]
DeserializationFailed(String),
#[error("Failed to push job to queue '{queue}': {message}")]
PushFailed {
queue: String,
message: String,
},
#[error("Failed to pop job from queue '{queue}': {message}")]
PopFailed {
queue: String,
message: String,
},
#[error("Job '{job}' failed: {message}")]
JobFailed {
job: String,
message: String,
},
#[error("Job '{job}' exceeded maximum retries ({max_retries})")]
MaxRetriesExceeded {
job: String,
max_retries: u32,
},
#[error("Redis error: {0}")]
Redis(#[from] redis::RedisError),
#[error("JSON error: {0}")]
Json(#[from] serde_json::Error),
#[error("Tenant not found for job: tenant_id={tenant_id}")]
TenantNotFound {
tenant_id: i64,
},
#[error("{0}")]
Custom(String),
}
impl Error {
pub fn job_failed(job: impl Into<String>, message: impl Into<String>) -> Self {
Self::JobFailed {
job: job.into(),
message: message.into(),
}
}
pub fn push_failed(queue: impl Into<String>, message: impl Into<String>) -> Self {
Self::PushFailed {
queue: queue.into(),
message: message.into(),
}
}
pub fn tenant_not_found(id: i64) -> Self {
Self::TenantNotFound { tenant_id: id }
}
pub fn custom(message: impl Into<String>) -> Self {
Self::Custom(message.into())
}
}
impl From<String> for Error {
fn from(s: String) -> Self {
Self::Custom(s)
}
}
impl From<&str> for Error {
fn from(s: &str) -> Self {
Self::Custom(s.to_string())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_tenant_not_found_formats_with_id() {
let err = Error::tenant_not_found(42);
assert_eq!(err.to_string(), "Tenant not found for job: tenant_id=42");
}
#[test]
fn test_tenant_not_found_constructor() {
let err = Error::tenant_not_found(99);
assert!(matches!(err, Error::TenantNotFound { tenant_id: 99 }));
}
}