1use std::time::Duration;
2use thiserror::Error;
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 { id: String, panic_info: String },
21
22 #[error("Pool exhausted: no available workers")]
23 PoolExhausted,
24
25 #[error("Configuration error: {0}")]
26 ConfigError(String),
27
28 #[error("Shutdown requested")]
29 Shutdown,
30
31 #[error("Serialization error: {0}")]
32 SerializationError(#[from] serde_json::Error),
33
34 #[error("Timeout error: {0}")]
35 Timeout(String),
36
37 #[error("Channel error: {0}")]
38 ChannelError(String),
39
40 #[error("Retryable failure: {source}. Retrying in {delay_ms:?}ms")]
41 RetryableFailure {
42 source: Box<WorkerError>,
43 delay_ms: Duration,
44 },
45
46 #[error("Retries exhausted for message: {source}")]
47 RetriesExhausted { source: Box<WorkerError> },
48
49 #[error("Message already acknowledged by middleware")]
50 AlreadyAcknowledged,
51
52 #[error("Application error: {0}")]
53 AppError(#[from] anyhow::Error),
54}
55
56pub type WorkerResult<T> = Result<T, WorkerError>;
58
59impl From<std::io::Error> for WorkerError {
64 fn from(err: std::io::Error) -> Self {
65 WorkerError::BackendError(err.to_string())
66 }
67}
68
69impl From<tokio::task::JoinError> for WorkerError {
70 fn from(err: tokio::task::JoinError) -> Self {
71 match err.try_into_panic() {
73 Ok(reason) => {
74 if let Some(s) = reason.downcast_ref::<String>() {
76 WorkerError::ProcessingFailed(format!("Task panicked: {}", s))
77 } else if let Some(s) = reason.downcast_ref::<&str>() {
78 WorkerError::ProcessingFailed(format!("Task panicked: {}", s))
79 } else {
80 WorkerError::ProcessingFailed("Task panicked with unknown reason".to_string())
81 }
82 }
83 Err(cancelled_err) => {
84 WorkerError::ProcessingFailed(format!("Task cancelled: {}", cancelled_err))
86 }
87 }
88 }
89}