dapr_durabletask/api/
errors.rs1use super::FailureDetails;
2
3#[derive(Debug, thiserror::Error)]
5pub enum DurableTaskError {
6 #[error("gRPC error: {0}")]
7 GrpcError(Box<tonic::Status>),
8
9 #[error("Orchestration '{instance_id}' failed: {message}")]
10 OrchestrationFailed {
11 instance_id: String,
12 message: String,
13 failure_details: Option<FailureDetails>,
14 },
15
16 #[error("Orchestration '{instance_id}' not found")]
17 InstanceNotFound { instance_id: String },
18
19 #[error("Task failed: {message}")]
20 TaskFailed {
21 message: String,
22 failure_details: Option<FailureDetails>,
23 },
24
25 #[error("Non-determinism error: {message}")]
26 NonDeterminism { message: String },
27
28 #[error("Orchestration state error: {message}")]
29 OrchestrationState { message: String },
30
31 #[error("Timeout waiting for orchestration")]
32 Timeout,
33
34 #[error("Serialisation error: {0}")]
35 Serialization(#[from] serde_json::Error),
36
37 #[error("{0}")]
38 Other(String),
39}
40
41impl From<tonic::Status> for DurableTaskError {
42 fn from(status: tonic::Status) -> Self {
43 DurableTaskError::GrpcError(Box::new(status))
44 }
45}
46
47pub type Result<T> = std::result::Result<T, DurableTaskError>;
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53
54 #[test]
55 fn display_grpc_error() {
56 let err = DurableTaskError::GrpcError(Box::new(tonic::Status::internal("oops")));
57 let msg = err.to_string();
58 assert!(msg.starts_with("gRPC error: "));
59 assert!(msg.contains("oops"));
60 }
61
62 #[test]
63 fn display_orchestration_failed() {
64 let err = DurableTaskError::OrchestrationFailed {
65 instance_id: "abc".into(),
66 message: "boom".into(),
67 failure_details: None,
68 };
69 assert_eq!(err.to_string(), "Orchestration 'abc' failed: boom");
70 }
71
72 #[test]
73 fn display_instance_not_found() {
74 let err = DurableTaskError::InstanceNotFound {
75 instance_id: "xyz".into(),
76 };
77 assert_eq!(err.to_string(), "Orchestration 'xyz' not found");
78 }
79
80 #[test]
81 fn display_task_failed() {
82 let err = DurableTaskError::TaskFailed {
83 message: "task err".into(),
84 failure_details: None,
85 };
86 assert_eq!(err.to_string(), "Task failed: task err");
87 }
88
89 #[test]
90 fn display_timeout() {
91 assert_eq!(
92 DurableTaskError::Timeout.to_string(),
93 "Timeout waiting for orchestration"
94 );
95 }
96
97 #[test]
98 fn display_other() {
99 let err = DurableTaskError::Other("custom".into());
100 assert_eq!(err.to_string(), "custom");
101 }
102
103 #[test]
104 fn from_tonic_status() {
105 let status = tonic::Status::internal("test");
106 let err: DurableTaskError = status.into();
107 matches!(err, DurableTaskError::GrpcError(_));
108 }
109
110 #[test]
111 fn from_serde_json_error() {
112 let json_err = serde_json::from_str::<String>("not valid json").unwrap_err();
113 let err: DurableTaskError = json_err.into();
114 matches!(err, DurableTaskError::Serialization(_));
115 }
116}