Skip to main content

reliar_core/
failure.rs

1//! Failure classification shared by [`crate::Publisher`] and `OutboxStore` (`reliar-outbox`)
2//! (ADR 0008, ADR 0032).
3
4/// Implemented by every [`crate::Publisher::Error`] and `OutboxStore::Error`
5/// (`reliar-outbox`) so a dispatcher can decide retry vs. dead without a downcast. Carried **by
6/// the error type**, not by the publisher: the error value is what crosses a `JoinSet` boundary
7/// into the dispatcher, so it must carry its own verdict (ADR 0008).
8///
9/// ```
10/// use reliar_core::{Classify, FailureKind};
11///
12/// #[derive(Debug)]
13/// enum MyPublishError {
14///     Timeout,
15///     PayloadTooLarge,
16/// }
17///
18/// impl Classify for MyPublishError {
19///     fn kind(&self) -> FailureKind {
20///         match self {
21///             Self::Timeout => FailureKind::Transient,
22///             Self::PayloadTooLarge => FailureKind::Permanent,
23///         }
24///     }
25/// }
26///
27/// assert_eq!(MyPublishError::Timeout.kind(), FailureKind::Transient);
28/// ```
29pub trait Classify {
30    /// Whether the failure this error represents can succeed on retry.
31    ///
32    /// ```
33    /// use reliar_core::{Classify, FailureKind};
34    ///
35    /// #[derive(Debug)]
36    /// struct TimedOut;
37    ///
38    /// impl Classify for TimedOut {
39    ///     fn kind(&self) -> FailureKind {
40    ///         FailureKind::Transient
41    ///     }
42    /// }
43    ///
44    /// assert_eq!(TimedOut.kind(), FailureKind::Transient);
45    /// ```
46    fn kind(&self) -> FailureKind;
47}
48
49/// Whether a failure is worth retrying.
50///
51/// ```
52/// use reliar_core::FailureKind;
53///
54/// assert_ne!(FailureKind::Transient, FailureKind::Permanent);
55/// ```
56#[derive(Clone, Copy, Debug, PartialEq, Eq)]
57pub enum FailureKind {
58    /// May succeed if retried (a timeout, a connection blip, a lock conflict).
59    Transient,
60
61    /// No retry can fix it (an oversized payload, an unresolvable schema).
62    Permanent,
63}