1use runifold_core::{JournalError, RunError};
2use thiserror::Error;
3
4#[derive(Clone, Debug, Eq, PartialEq)]
6#[non_exhaustive]
7pub enum EffectExecutorErrorKind {
8 CapabilityDenied,
10 IdempotencyConflict,
12 Ambiguous,
14 Store,
16 Observability,
18 Handler,
20 Cancelled,
22 DeadlineExceeded,
24 Protocol,
26 Reconciliation,
28}
29
30#[derive(Clone, Debug, Error, PartialEq)]
32#[error("{kind:?}: {message}")]
33pub struct EffectExecutorError {
34 pub kind: EffectExecutorErrorKind,
36 pub message: String,
38 #[source]
40 pub source_error: Option<RunError>,
41}
42
43impl EffectExecutorError {
44 pub const fn diagnostic_code(&self) -> &'static str {
49 match self.kind {
50 EffectExecutorErrorKind::CapabilityDenied => "RF-EFFECT-001",
51 EffectExecutorErrorKind::IdempotencyConflict => "RF-EFFECT-002",
52 EffectExecutorErrorKind::Ambiguous => "RF-EFFECT-003",
53 EffectExecutorErrorKind::Store => "RF-EFFECT-004",
54 EffectExecutorErrorKind::Observability => "RF-EFFECT-005",
55 EffectExecutorErrorKind::Handler => "RF-EFFECT-006",
56 EffectExecutorErrorKind::Cancelled => "RF-EFFECT-007",
57 EffectExecutorErrorKind::DeadlineExceeded => "RF-EFFECT-008",
58 EffectExecutorErrorKind::Protocol => "RF-EFFECT-009",
59 EffectExecutorErrorKind::Reconciliation => "RF-EFFECT-010",
60 }
61 }
62
63 pub fn new(kind: EffectExecutorErrorKind, message: impl Into<String>) -> Self {
65 Self {
66 kind,
67 message: message.into(),
68 source_error: None,
69 }
70 }
71
72 pub(crate) fn handler(error: RunError) -> Self {
73 Self {
74 kind: EffectExecutorErrorKind::Handler,
75 message: error.to_string(),
76 source_error: Some(error),
77 }
78 }
79
80 pub(crate) fn reconciliation(error: RunError) -> Self {
81 Self {
82 kind: EffectExecutorErrorKind::Reconciliation,
83 message: error.to_string(),
84 source_error: Some(error),
85 }
86 }
87
88 pub(crate) fn ambiguous_handler(error: RunError) -> Self {
89 Self {
90 kind: EffectExecutorErrorKind::Ambiguous,
91 message: "effect handler failed after the remote outcome became uncertain".into(),
92 source_error: Some(error),
93 }
94 }
95}
96
97impl From<JournalError> for EffectExecutorError {
98 fn from(error: JournalError) -> Self {
99 Self::new(EffectExecutorErrorKind::Observability, error.to_string())
100 }
101}