llm_incident_manager/integrations/common/
errors.rs

1use thiserror::Error;
2
3/// Integration-specific error types
4#[derive(Error, Debug)]
5pub enum IntegrationError {
6    /// Connection errors
7    #[error("Connection error: {0}")]
8    Connection(String),
9
10    /// Request failed
11    #[error("Request failed: {0}")]
12    RequestFailed(String),
13
14    /// Invalid response
15    #[error("Invalid response: {0}")]
16    InvalidResponse(String),
17
18    /// Timeout error
19    #[error("Operation timed out after {timeout_secs} seconds")]
20    Timeout { timeout_secs: u64 },
21
22    /// Retry exhausted
23    #[error("Retry exhausted for {operation} after {attempts} attempts")]
24    RetryExhausted { operation: String, attempts: u32 },
25
26    /// Configuration error
27    #[error("Configuration error: {0}")]
28    Configuration(String),
29
30    /// Authentication error
31    #[error("Authentication error: {0}")]
32    Authentication(String),
33
34    /// Rate limit exceeded
35    #[error("Rate limit exceeded: {0}")]
36    RateLimit(String),
37
38    /// Network error
39    #[error("Network error: {0}")]
40    Network(String),
41
42    /// Serialization error
43    #[error("Serialization error: {0}")]
44    Serialization(String),
45
46    /// Internal error
47    #[error("Internal error: {0}")]
48    Internal(String),
49}
50
51impl IntegrationError {
52    /// Check if error is retryable
53    pub fn is_retryable(&self) -> bool {
54        matches!(
55            self,
56            IntegrationError::Connection(_)
57                | IntegrationError::Network(_)
58                | IntegrationError::Timeout { .. }
59        )
60    }
61}
62
63/// Result type for integration operations
64pub type IntegrationResult<T> = Result<T, IntegrationError>;
65
66/// Convert from tonic::Status to IntegrationError
67impl From<tonic::Status> for IntegrationError {
68    fn from(status: tonic::Status) -> Self {
69        use tonic::Code;
70        match status.code() {
71            Code::Unauthenticated => {
72                IntegrationError::Authentication(status.message().to_string())
73            }
74            Code::Unavailable => IntegrationError::Connection(status.message().to_string()),
75            Code::DeadlineExceeded => IntegrationError::Timeout { timeout_secs: 0 },
76            Code::ResourceExhausted => IntegrationError::RateLimit(status.message().to_string()),
77            _ => IntegrationError::RequestFailed(status.message().to_string()),
78        }
79    }
80}
81
82/// Convert IntegrationError to AppError
83impl From<IntegrationError> for crate::error::AppError {
84    fn from(err: IntegrationError) -> Self {
85        match err {
86            IntegrationError::Connection(msg) => crate::error::AppError::Network(msg),
87            IntegrationError::RequestFailed(msg) => crate::error::AppError::Integration {
88                integration_source: "LLM".to_string(),
89                message: msg,
90            },
91            IntegrationError::InvalidResponse(msg) => crate::error::AppError::Integration {
92                integration_source: "LLM".to_string(),
93                message: msg,
94            },
95            IntegrationError::Timeout { timeout_secs } => {
96                crate::error::AppError::Timeout(format!("Timeout after {} seconds", timeout_secs))
97            }
98            IntegrationError::RetryExhausted { operation, attempts } => {
99                crate::error::AppError::Integration {
100                    integration_source: "LLM".to_string(),
101                    message: format!("Retry exhausted for {} after {} attempts", operation, attempts),
102                }
103            }
104            IntegrationError::Configuration(msg) => crate::error::AppError::Configuration(msg),
105            IntegrationError::Authentication(msg) => crate::error::AppError::Authentication(msg),
106            IntegrationError::RateLimit(msg) => crate::error::AppError::Integration {
107                integration_source: "LLM".to_string(),
108                message: format!("Rate limit: {}", msg),
109            },
110            IntegrationError::Network(msg) => crate::error::AppError::Network(msg),
111            IntegrationError::Serialization(msg) => crate::error::AppError::Serialization(msg),
112            IntegrationError::Internal(msg) => crate::error::AppError::Internal(msg),
113        }
114    }
115}