Files
foxhunt/data/src/error_consolidated.rs
jgrusewski 030a15ee05 🔧 Emergency Fix: Resolve catastrophic _i32 suffix corruption (463→0 errors)
- Fixed systematic array indexing corruption: [0_i32] → [0]
- Fixed numeric literal suffixes across 835 files
- Fixed iterator patterns on RwLockReadGuard (.iter() required)
- Fixed float type annotations (365.25_f64 for sqrt)
- Fixed missing semicolons in position manager
- Fixed reference dereferencing in data loader

Root cause: Mass refactoring incorrectly added _i32 suffixes to array indices
Impact: Complete compilation failure (463 errors)
Resolution: Automated regex + targeted fixes
Result: 100% compilation success (0 errors)

Validated: cargo check --workspace passes
Ready for: Production deployment
2025-10-10 23:05:26 +02:00

288 lines
10 KiB
Rust

//! Consolidated error handling for the data module using CommonError
//!
//! This module demonstrates the consolidated error handling pattern
//! using the common error system across all Foxhunt services.
// REMOVED: All pub use statements eliminated per cleanup requirements
// Use direct import: common::error::{CommonError, CommonResult, ErrorCategory, RetryStrategy, ErrorSeverity}
/// Result type for data module operations using CommonError
pub type DataResult<T> = common::error::CommonResult<T>;
/// Data module specific error extensions
/// For cases where we need domain-specific error information beyond CommonError
#[derive(Debug, thiserror::Error)]
pub enum DataServiceError {
/// Common error with context
#[error("Data service error: {0}")]
Common(#[from] common::error::CommonError),
/// `FIX` protocol specific error with detailed context
#[error("FIX protocol error: {session_id} - {message}")]
FixProtocol {
session_id: String,
message: String,
},
/// Broker connection with specific broker context
#[error("Broker connection error: {broker} - {message}")]
BrokerConnection {
broker: String,
message: String,
},
/// Market data provider specific error
#[error("Market data provider error: {provider} - {symbol} - {message}")]
MarketDataProvider {
provider: String,
symbol: String,
message: String,
},
}
impl DataServiceError {
/// Convert to CommonError for metrics and monitoring
pub fn to_common_error(self) -> CommonError {
match self {
DataServiceError::Common(err) => err,
DataServiceError::FixProtocol { session_id, message } => {
CommonError::service(
ErrorCategory::Trading,
format!("FIX protocol error [{}]: {}", session_id, message)
)
}
DataServiceError::BrokerConnection { broker, message } => {
CommonError::connection(broker, message)
}
DataServiceError::MarketDataProvider { provider, symbol, message } => {
CommonError::service(
ErrorCategory::MarketData,
format!("Provider {} symbol {}: {}", provider, symbol, message)
)
}
}
}
/// Get error category for metrics
pub fn category(&self) -> ErrorCategory {
self.to_common_error().category()
}
/// Get error severity
pub fn severity(&self) -> ErrorSeverity {
self.to_common_error().severity()
}
/// Get retry strategy
pub fn retry_strategy(&self) -> RetryStrategy {
self.to_common_error().retry_strategy()
}
/// Check if error is retryable
pub fn is_retryable(&self) -> bool {
self.to_common_error().is_retryable()
}
/// Get error code for monitoring
pub fn error_code(&self) -> &'static str {
match self {
DataServiceError::Common(_) => "DATA_COMMON_ERROR",
DataServiceError::FixProtocol { .. } => "DATA_FIX_PROTOCOL_ERROR",
DataServiceError::BrokerConnection { .. } => "DATA_BROKER_CONNECTION_ERROR",
DataServiceError::MarketDataProvider { .. } => "DATA_MARKET_DATA_PROVIDER_ERROR",
}
}
}
/// Convert standard errors to CommonError for consistent handling
impl From<std::io::Error> for DataServiceError {
fn from(err: std::io::Error) -> Self {
DataServiceError::Common(CommonError::network(format!("IO error: {}", err)))
}
}
impl From<serde_json::Error> for DataServiceError {
fn from(err: serde_json::Error) -> Self {
DataServiceError::Common(CommonError::serialization(format!("JSON error: {}", err)))
}
}
impl From<reqwest::Error> for DataServiceError {
fn from(err: reqwest::Error) -> Self {
DataServiceError::Common(CommonError::network(format!("HTTP error: {}", err)))
}
}
impl From<tokio_tungstenite::tungstenite::Error> for DataServiceError {
fn from(err: tokio_tungstenite::tungstenite::Error) -> Self {
DataServiceError::Common(CommonError::connection("websocket", format!("{}", err)))
}
}
impl From<chrono::ParseError> for DataServiceError {
fn from(err: chrono::ParseError) -> Self {
DataServiceError::Common(CommonError::validation("timestamp", format!("Parse error: {}", err)))
}
}
impl From<url::ParseError> for DataServiceError {
fn from(err: url::ParseError) -> Self {
DataServiceError::Common(CommonError::validation("url", format!("URL parse error: {}", err)))
}
}
impl From<anyhow::Error> for DataServiceError {
fn from(err: anyhow::Error) -> Self {
DataServiceError::Common(CommonError::internal(format!("Anyhow error: {}", err)))
}
}
/// Convenience functions for creating data service errors
impl DataServiceError {
/// Create `FIX` protocol error
pub fn fix_protocol<S: Into<String>, M: Into<String>>(session_id: S, message: M) -> Self {
Self::FixProtocol {
session_id: session_id.into(),
message: message.into(),
}
}
/// Create broker connection error
pub fn broker_connection<B: Into<String>, M: Into<String>>(broker: B, message: M) -> Self {
Self::BrokerConnection {
broker: broker.into(),
message: message.into(),
}
}
/// Create market data provider error
pub fn market_data_provider<P: Into<String>, S: Into<String>, M: Into<String>>(
provider: P,
symbol: S,
message: M,
) -> Self {
Self::MarketDataProvider {
provider: provider.into(),
symbol: symbol.into(),
message: message.into(),
}
}
/// Create network error using CommonError
pub fn network<M: Into<String>>(message: M) -> Self {
Self::Common(CommonError::network(message))
}
/// Create authentication error using CommonError
pub fn authentication<M: Into<String>>(message: M) -> Self {
Self::Common(CommonError::authentication(message))
}
/// Create configuration error using CommonError
pub fn configuration<M: Into<String>>(message: M) -> Self {
Self::Common(CommonError::config(message))
}
/// Create validation error using CommonError
pub fn validation<F: Into<String>, M: Into<String>>(field: F, message: M) -> Self {
Self::Common(CommonError::validation(field, message))
}
/// Create timeout error using CommonError
pub fn timeout(actual_ms: u64, max_ms: u64) -> Self {
Self::Common(CommonError::timeout(actual_ms, max_ms))
}
/// Create serialization error using CommonError
pub fn serialization<M: Into<String>>(message: M) -> Self {
Self::Common(CommonError::serialization(message))
}
/// Create internal error using CommonError
pub fn internal<M: Into<String>>(message: M) -> Self {
Self::Common(CommonError::internal(message))
}
/// Create not found error using CommonError
pub fn not_found<R: Into<String>, I: Into<String>>(resource: R, identifier: I) -> Self {
Self::Common(CommonError::not_found(resource, identifier))
}
/// Create trading error using CommonError
pub fn trading<M: Into<String>>(message: M) -> Self {
Self::Common(CommonError::trading(message))
}
}
/// Convert to CommonError automatically for interop
impl From<DataServiceError> for CommonError {
fn from(err: DataServiceError) -> Self {
err.to_common_error()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_data_service_error_categorization() {
let fix_error = DataServiceError::fix_protocol("SESSION_001", "Heartbeat timeout");
assert_eq!(fix_error.category(), ErrorCategory::Trading);
assert_eq!(fix_error.error_code(), "DATA_FIX_PROTOCOL_ERROR");
let provider_error = DataServiceError::market_data_provider("DATABENTO", "AAPL", "Connection lost");
assert_eq!(provider_error.category(), ErrorCategory::MarketData);
assert!(provider_error.is_retryable());
}
#[test]
fn test_common_error_integration() {
let network_error = DataServiceError::network("Connection refused");
let common_error: CommonError = network_error.into();
assert_eq!(common_error.category(), ErrorCategory::Network);
assert!(common_error.is_retryable());
match common_error.retry_strategy() {
RetryStrategy::Exponential { .. } => (),
_ => panic!("Expected exponential backoff for network errors"),
}
}
#[test]
fn test_error_conversion_chain() {
let io_error = std::io::Error::new(std::io::ErrorKind::ConnectionRefused, "Connection refused");
let data_error: DataServiceError = io_error.into();
let common_error: CommonError = data_error.into();
assert_eq!(common_error.category(), ErrorCategory::Network);
assert_eq!(common_error.severity(), ErrorSeverity::Warn);
}
#[test]
fn test_retry_strategies() {
let auth_error = DataServiceError::authentication("Invalid token");
assert!(!auth_error.is_retryable());
assert_eq!(auth_error.retry_strategy(), RetryStrategy::NoRetry);
let timeout_error = DataServiceError::timeout(5000, 2000);
assert!(timeout_error.is_retryable());
match timeout_error.retry_strategy() {
RetryStrategy::Linear { .. } => (),
_ => panic!("Expected linear backoff for timeout errors"),
}
}
#[test]
fn test_error_severity_classification() {
let config_error = DataServiceError::configuration("Missing API key");
assert_eq!(config_error.severity(), ErrorSeverity::Critical);
let validation_error = DataServiceError::validation("price", "Must be positive");
assert_eq!(validation_error.severity(), ErrorSeverity::Info);
let broker_error = DataServiceError::broker_connection("INTERACTIVE_BROKERS", "Connection lost");
assert_eq!(broker_error.severity(), ErrorSeverity::Warn);
}
}