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}