1use thiserror::Error;
2use std::time::Duration;
3
4#[derive(Debug, Error)]
6pub enum WorkerError {
7 #[error("Message processing failed: {0}")]
8 ProcessingFailed(String),
9
10 #[error("Processing error: {0}")]
11 ProcessingError(String),
12
13 #[error("Backend error: {0}")]
14 BackendError(String),
15
16 #[error("Acknowledgment failed: {0}")]
17 AcknowledgmentFailed(String),
18
19 #[error("Worker {id} panicked: {panic_info}")]
20 WorkerPanic {
21 id: String,
22 panic_info: String,
23 },
24
25 #[error("Pool exhausted: no available workers")]
26 PoolExhausted,
27
28 #[error("Configuration error: {0}")]
29 ConfigError(String),
30
31 #[error("Shutdown requested")]
32 Shutdown,
33
34 #[error("Serialization error: {0}")]
35 SerializationError(#[from] serde_json::Error),
36
37 #[error("Timeout error: {0}")]
38 Timeout(String),
39
40 #[error("Channel error: {0}")]
41 ChannelError(String),
42
43 #[error("Retryable failure: {source}. Retrying in {delay_ms:?}ms")]
44 RetryableFailure {
45 source: Box<WorkerError>,
46 delay_ms: Duration,
47 },
48
49 #[error("Retries exhausted for message: {source}")]
50 RetriesExhausted {
51 source: Box<WorkerError>,
52 },
53
54 #[error("Message already acknowledged by middleware")]
55 AlreadyAcknowledged,
56
57 #[error("Application error: {0}")]
58 AppError(#[from] anyhow::Error),
59}
60
61pub type WorkerResult<T> = Result<T, WorkerError>;
63
64impl From<std::io::Error> for WorkerError {
69 fn from(err: std::io::Error) -> Self {
70 WorkerError::BackendError(err.to_string())
71 }
72}
73
74impl From<tokio::task::JoinError> for WorkerError {
75 fn from(err: tokio::task::JoinError) -> Self {
76 match err.try_into_panic() {
78 Ok(reason) => {
79 if let Some(s) = reason.downcast_ref::<String>() {
81 WorkerError::ProcessingFailed(format!("Task panicked: {}", s))
82 } else if let Some(s) = reason.downcast_ref::<&str>() {
83 WorkerError::ProcessingFailed(format!("Task panicked: {}", s))
84 } else {
85 WorkerError::ProcessingFailed("Task panicked with unknown reason".to_string())
86 }
87 }
88 Err(cancelled_err) => {
89 WorkerError::ProcessingFailed(format!("Task cancelled: {}", cancelled_err))
91 }
92 }
93 }
94}