Skip to content

Commit aa0d4ca

Browse files
authored
fix: add BACKEND_TIMEOUT error code with proper error handling (#17)
- Add BACKEND_TIMEOUT error code constant (-32011) to error_codes module - Add explicit BackendTimeout match arm in to_error_payload() - Use inline format args for consistency - Add test coverage for BackendTimeout error code and payload message
1 parent 1defb22 commit aa0d4ca

1 file changed

Lines changed: 25 additions & 6 deletions

File tree

crates/types/src/error.rs

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ pub mod error_codes {
1111
pub const RATE_LIMITED: i64 = -32016;
1212
/// Backend offline error code.
1313
pub const BACKEND_OFFLINE: i64 = -32010;
14+
/// Backend timeout error code.
15+
pub const BACKEND_TIMEOUT: i64 = -32011;
1416
}
1517

1618
/// Error type for the Roxy proxy.
@@ -58,19 +60,24 @@ impl RoxyError {
5860
match self {
5961
Self::RateLimited { retry_after } => ErrorPayload {
6062
code: error_codes::RATE_LIMITED,
61-
message: format!("rate limited, retry after {:?}", retry_after).into(),
63+
message: format!("rate limited, retry after {retry_after:?}").into(),
6264
data: None,
6365
},
6466
Self::BackendOffline { backend } => ErrorPayload {
6567
code: error_codes::BACKEND_OFFLINE,
66-
message: format!("backend {} is offline", backend).into(),
68+
message: format!("backend {backend} is offline").into(),
6769
data: None,
6870
},
6971
Self::NoHealthyBackends => ErrorPayload {
7072
code: error_codes::BACKEND_OFFLINE,
7173
message: "no healthy backends".into(),
7274
data: None,
7375
},
76+
Self::BackendTimeout { backend } => ErrorPayload {
77+
code: error_codes::BACKEND_TIMEOUT,
78+
message: format!("backend {backend} timed out").into(),
79+
data: None,
80+
},
7481
_ => ErrorPayload::internal_error(),
7582
}
7683
}
@@ -88,7 +95,6 @@ mod tests {
8895

8996
use super::*;
9097

91-
/// Test that should_failover returns the expected value for each error type.
9298
#[rstest]
9399
#[case::rate_limited(RoxyError::RateLimited { retry_after: Duration::from_secs(5) }, false)]
94100
#[case::backend_offline(RoxyError::BackendOffline { backend: "primary".to_string() }, true)]
@@ -100,10 +106,10 @@ mod tests {
100106
assert_eq!(error.should_failover(), expected);
101107
}
102108

103-
/// Test that to_error_payload returns the expected error code for each error type.
104109
#[rstest]
105110
#[case::rate_limited(RoxyError::RateLimited { retry_after: Duration::from_secs(5) }, error_codes::RATE_LIMITED)]
106111
#[case::backend_offline(RoxyError::BackendOffline { backend: "primary".to_string() }, error_codes::BACKEND_OFFLINE)]
112+
#[case::backend_timeout(RoxyError::BackendTimeout { backend: "slow".to_string() }, error_codes::BACKEND_TIMEOUT)]
107113
#[case::no_healthy_backends(RoxyError::NoHealthyBackends, error_codes::BACKEND_OFFLINE)]
108114
#[case::cache_error(RoxyError::CacheError("connection failed".to_string()), -32603)]
109115
#[case::internal_error(RoxyError::Internal("unexpected state".to_string()), -32603)]
@@ -112,7 +118,6 @@ mod tests {
112118
assert_eq!(payload.code, expected_code);
113119
}
114120

115-
/// Test that error Display messages contain expected substrings.
116121
#[rstest]
117122
#[case::rate_limited(RoxyError::RateLimited { retry_after: Duration::from_secs(5) }, "rate limited")]
118123
#[case::backend_offline(RoxyError::BackendOffline { backend: "primary".to_string() }, "primary")]
@@ -129,7 +134,6 @@ mod tests {
129134
);
130135
}
131136

132-
/// Test that backend offline error payload message contains the backend name.
133137
#[rstest]
134138
#[case::primary("primary")]
135139
#[case::secondary("secondary")]
@@ -144,4 +148,19 @@ mod tests {
144148
backend_name
145149
);
146150
}
151+
152+
#[rstest]
153+
#[case::primary("primary")]
154+
#[case::secondary("secondary")]
155+
#[case::node_1("node-1")]
156+
fn test_backend_timeout_payload_contains_name(#[case] backend_name: &str) {
157+
let err = RoxyError::BackendTimeout { backend: backend_name.to_string() };
158+
let payload = err.to_error_payload();
159+
assert!(
160+
payload.message.contains(backend_name),
161+
"Expected payload message '{}' to contain '{}'",
162+
payload.message,
163+
backend_name
164+
);
165+
}
147166
}

0 commit comments

Comments
 (0)