1use crate::message::Timestamp;
4use chrono::Duration;
5use thiserror::Error;
6
7#[derive(Debug, Error)]
9pub enum QueueError {
10 #[error("Queue not found: {queue_name}")]
11 QueueNotFound { queue_name: String },
12
13 #[error("Message not found: {receipt}")]
14 MessageNotFound { receipt: String },
15
16 #[error("Invalid or expired receipt handle: {receipt}")]
17 InvalidReceipt { receipt: String },
18
19 #[error("Session '{session_id}' is locked until {locked_until}")]
20 SessionLocked {
21 session_id: String,
22 locked_until: Timestamp,
23 },
24
25 #[error("Session '{session_id}' not found or expired")]
26 SessionNotFound { session_id: String },
27
28 #[error("Operation timed out after {duration:?}")]
29 Timeout { duration: Duration },
30
31 #[error("Connection failed: {message}")]
32 ConnectionFailed { message: String },
33
34 #[error("Authentication failed: {message}")]
35 AuthenticationFailed { message: String },
36
37 #[error("Permission denied for operation: {operation}")]
38 PermissionDenied { operation: String },
39
40 #[error("Message too large: {size} bytes (max: {max_size})")]
41 MessageTooLarge { size: usize, max_size: usize },
42
43 #[error("Batch size {size} exceeds maximum {max_size}")]
44 BatchTooLarge { size: usize, max_size: usize },
45
46 #[error("Provider error ({provider}): {code} - {message}")]
47 ProviderError {
48 provider: String,
49 code: String,
50 message: String,
51 },
52
53 #[error("Serialization failed: {0}")]
54 SerializationError(#[from] SerializationError),
55
56 #[error("Configuration error: {0}")]
57 ConfigurationError(#[from] ConfigurationError),
58
59 #[error("Validation error: {0}")]
60 ValidationError(#[from] ValidationError),
61}
62
63impl QueueError {
64 pub fn is_transient(&self) -> bool {
66 match self {
67 Self::QueueNotFound { .. } => false,
68 Self::MessageNotFound { .. } => false,
69 Self::InvalidReceipt { .. } => false,
70 Self::SessionLocked { .. } => true,
71 Self::SessionNotFound { .. } => false,
72 Self::Timeout { .. } => true,
73 Self::ConnectionFailed { .. } => true,
74 Self::AuthenticationFailed { .. } => false,
75 Self::PermissionDenied { .. } => false,
76 Self::MessageTooLarge { .. } => false,
77 Self::BatchTooLarge { .. } => false,
78 Self::ProviderError { .. } => true, Self::SerializationError(_) => false,
80 Self::ConfigurationError(_) => false,
81 Self::ValidationError(_) => false,
82 }
83 }
84
85 pub fn should_retry(&self) -> bool {
87 self.is_transient()
88 }
89
90 pub fn retry_after(&self) -> Option<Duration> {
92 match self {
93 Self::SessionLocked { .. } => Some(Duration::seconds(5)),
94 Self::Timeout { .. } => Some(Duration::seconds(1)),
95 Self::ConnectionFailed { .. } => Some(Duration::seconds(5)),
96 _ => None,
97 }
98 }
99}
100
101#[derive(Debug, Error)]
103pub enum SerializationError {
104 #[error("JSON serialization failed: {0}")]
105 JsonError(#[from] serde_json::Error),
106
107 #[error("Message body is not valid UTF-8")]
108 InvalidUtf8,
109
110 #[error("Message attribute '{key}' has invalid value")]
111 InvalidAttribute { key: String },
112
113 #[error("Message exceeds size limit: {size} bytes")]
114 MessageTooLarge { size: usize },
115}
116
117#[derive(Debug, Error)]
119pub enum ConfigurationError {
120 #[error("Invalid configuration: {message}")]
121 Invalid { message: String },
122
123 #[error("Missing required configuration: {key}")]
124 Missing { key: String },
125
126 #[error("Configuration parsing failed: {message}")]
127 Parsing { message: String },
128
129 #[error("Unsupported provider: {provider} - {message}")]
130 UnsupportedProvider { provider: String, message: String },
131}
132
133#[derive(Debug, Error)]
135pub enum ValidationError {
136 #[error("Required field missing: {field}")]
137 Required { field: String },
138
139 #[error("Invalid format for {field}: {message}")]
140 InvalidFormat { field: String, message: String },
141
142 #[error("Value out of range for {field}: {message}")]
143 OutOfRange { field: String, message: String },
144}
145
146#[cfg(test)]
147#[path = "error_tests.rs"]
148mod tests;