Skip to main content

queue_runtime/
error.rs

1//! Error types for queue operations.
2
3use crate::message::Timestamp;
4use chrono::Duration;
5use thiserror::Error;
6
7/// Comprehensive error type for all queue operations
8#[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    /// Check if error is transient and should be retried
65    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, // Provider-specific errors are usually transient
79            Self::SerializationError(_) => false,
80            Self::ConfigurationError(_) => false,
81            Self::ValidationError(_) => false,
82        }
83    }
84
85    /// Check if error should be retried
86    pub fn should_retry(&self) -> bool {
87        self.is_transient()
88    }
89
90    /// Get suggested retry delay
91    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/// Errors during message serialization/deserialization
102#[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/// Configuration errors
118#[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/// Validation errors
134#[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;