Skip to main content

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}