1use sayiir_core::InvalidInstanceId;
4use sayiir_core::error::{BoxError, BuildError, BuildErrors, CodecError, WorkflowError};
5use sayiir_persistence::{BackendError, RunConflict};
6
7#[derive(Debug, thiserror::Error)]
12pub enum RuntimeError {
13 #[error(transparent)]
15 Workflow(#[from] WorkflowError),
16
17 #[error(transparent)]
19 Build(#[from] BuildErrors),
20
21 #[error(transparent)]
23 Backend(#[from] BackendError),
24
25 #[error(transparent)]
27 Codec(#[from] CodecError),
28
29 #[error(transparent)]
31 Task(BoxError),
32
33 #[error(transparent)]
35 Join(#[from] tokio::task::JoinError),
36
37 #[error("Workflow instance already exists: {0}")]
39 InstanceAlreadyExists(String),
40
41 #[error(transparent)]
43 InvalidInstanceId(#[from] InvalidInstanceId),
44}
45
46impl From<BoxError> for RuntimeError {
47 fn from(err: BoxError) -> Self {
48 match err.downcast::<CodecError>() {
49 Ok(codec_err) => Self::Codec(*codec_err),
50 Err(other) => Self::Task(other),
51 }
52 }
53}
54
55impl From<BuildError> for RuntimeError {
56 fn from(error: BuildError) -> Self {
57 Self::Build(BuildErrors::from(error))
58 }
59}
60
61impl From<RunConflict> for RuntimeError {
62 fn from(error: RunConflict) -> Self {
63 match error {
64 RunConflict::InvalidInstanceId(e) => Self::InvalidInstanceId(e),
65 RunConflict::AlreadyExists(id) => Self::InstanceAlreadyExists(id),
66 RunConflict::DefinitionMismatch { expected, found } => {
67 Self::Workflow(WorkflowError::DefinitionMismatch { expected, found })
68 }
69 RunConflict::Backend(e) => Self::Backend(e),
70 }
71 }
72}
73
74impl RuntimeError {
75 #[must_use]
77 pub fn is_timeout(&self) -> bool {
78 matches!(self, Self::Workflow(WorkflowError::TaskTimedOut { .. }))
79 }
80
81 #[must_use]
83 pub fn is_decode_error(&self) -> bool {
84 matches!(self, Self::Codec(CodecError::DecodeFailed { .. }))
85 }
86}