rskit_messaging/errors.rs
1//! Error classification for retry and circuit-breaker decisions.
2
3use rskit_errors::AppError;
4
5/// Classifies errors for retry and circuit-breaker decisions.
6///
7/// Broker adapters implement this trait so that generic retry policies and
8/// circuit breakers can decide how to handle a particular failure without
9/// knowing which broker produced it.
10pub trait ErrorClassifier: Send + Sync {
11 /// Returns `true` when the error indicates the broker connection is down
12 /// (e.g. TCP reset, DNS failure, authentication timeout).
13 fn is_connection_error(&self, err: &AppError) -> bool;
14
15 /// Returns `true` when the error is transient and the operation can be
16 /// retried (e.g. leader election in progress, throttling, temporary I/O
17 /// error). Connection errors are typically retryable too, but the
18 /// distinction lets callers apply different back-off strategies.
19 fn is_retryable_error(&self, err: &AppError) -> bool;
20}
21
22/// A no-op classifier that considers every error non-retryable.
23///
24/// Useful as a default when no broker-specific classifier is available.
25#[derive(Debug, Clone, Copy, Default)]
26pub struct NoopErrorClassifier;
27
28impl ErrorClassifier for NoopErrorClassifier {
29 fn is_connection_error(&self, _err: &AppError) -> bool {
30 false
31 }
32
33 fn is_retryable_error(&self, _err: &AppError) -> bool {
34 false
35 }
36}
37
38#[cfg(test)]
39mod tests {
40 use rskit_errors::{AppError, ErrorCode};
41
42 use super::*;
43
44 #[test]
45 fn noop_classifier_returns_false() {
46 let classifier = NoopErrorClassifier;
47 let err = AppError::new(ErrorCode::Internal, "something broke");
48
49 assert!(!classifier.is_connection_error(&err));
50 assert!(!classifier.is_retryable_error(&err));
51 }
52}