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 fn new(kind: EffectExecutorErrorKind, message: impl Into<String>) -> Self {
46 Self {
47 kind,
48 message: message.into(),
49 source_error: None,
50 }
51 }
52
53 pub(crate) fn handler(error: RunError) -> Self {
54 Self {
55 kind: EffectExecutorErrorKind::Handler,
56 message: error.to_string(),
57 source_error: Some(error),
58 }
59 }
60
61 pub(crate) fn reconciliation(error: RunError) -> Self {
62 Self {
63 kind: EffectExecutorErrorKind::Reconciliation,
64 message: error.to_string(),
65 source_error: Some(error),
66 }
67 }
68
69 pub(crate) fn ambiguous_handler(error: RunError) -> Self {
70 Self {
71 kind: EffectExecutorErrorKind::Ambiguous,
72 message: "effect handler failed after the remote outcome became uncertain".into(),
73 source_error: Some(error),
74 }
75 }
76}
77
78impl From<JournalError> for EffectExecutorError {
79 fn from(error: JournalError) -> Self {
80 Self::new(EffectExecutorErrorKind::Observability, error.to_string())
81 }
82}