1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
use std::fmt;
use std::time::Duration;
/// Error category codes inspired by gRPC status codes.
/// Used in `ActorError` to classify the failure type.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ErrorCode {
/// Unexpected internal error.
Internal,
/// Invalid argument provided by the caller.
InvalidArgument,
/// The requested actor or resource was not found.
NotFound,
/// The actor is temporarily unavailable (e.g., overloaded).
Unavailable,
/// The operation timed out.
Timeout,
/// The caller lacks permission for this operation.
PermissionDenied,
/// A precondition for the operation was not met.
FailedPrecondition,
/// A resource limit was exceeded (e.g., rate limit, quota).
ResourceExhausted,
/// The operation is not implemented by this actor/adapter.
Unimplemented,
/// Unknown error category.
Unknown,
/// The operation was cancelled.
Cancelled,
}
/// Error returned when sending a message to an actor fails.
///
/// Common causes: the actor has stopped, the mailbox is full (bounded),
/// or the mailbox channel is closed.
#[derive(Debug, Clone)]
pub struct ActorSendError(pub String);
impl fmt::Display for ActorSendError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "actor send failed: {}", self.0)
}
}
impl std::error::Error for ActorSendError {}
/// Error returned by processing group operations such as join, leave,
/// broadcast, or member enumeration.
#[derive(Debug, Clone)]
pub struct GroupError(pub String);
impl fmt::Display for GroupError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "group error: {}", self.0)
}
}
impl std::error::Error for GroupError {}
/// Error returned by cluster event subscription and unsubscription operations.
#[derive(Debug, Clone)]
pub struct ClusterError(pub String);
impl fmt::Display for ClusterError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "cluster error: {}", self.0)
}
}
impl std::error::Error for ClusterError {}
/// What the runtime should do after a handler error or panic.
///
/// Returned by [`Actor::on_error`](crate::actor::Actor::on_error) to let
/// the actor choose its own recovery strategy.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ErrorAction {
/// Skip the failed message and continue processing the next one.
Resume,
/// Restart the actor (re-run `create` + `on_start`), then continue.
Restart,
/// Stop the actor permanently.
Stop,
/// Propagate the error to the actor's supervisor (parent).
Escalate,
}
/// Error returned when a runtime capability is not supported by the adapter.
#[derive(Debug, Clone)]
pub struct NotSupportedError {
/// The capability that is not supported.
pub capability: String,
/// Detailed description of why it is not supported.
pub message: String,
}
impl fmt::Display for NotSupportedError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "not supported: {} — {}", self.capability, self.message)
}
}
impl std::error::Error for NotSupportedError {}
/// Unified error returned by runtime operations (ask, stream, feed, etc.).
///
/// Covers all failure modes: delivery errors, timeouts, interceptor
/// rejections, and handler-level actor errors.
#[derive(Debug)]
pub enum RuntimeError {
/// Message delivery failed (actor stopped, mailbox full, etc.)
Send(ActorSendError),
/// The target actor was not found or has stopped.
ActorNotFound(String),
/// The operation timed out.
Timeout,
/// The operation was rejected by an interceptor.
Rejected {
/// Name of the interceptor that rejected the message.
interceptor: String,
/// Reason the message was rejected.
reason: String,
},
/// An interceptor suggests the caller retry after the given duration.
/// The message was NOT delivered.
RetryAfter {
/// Name of the interceptor that requested the retry.
interceptor: String,
/// Suggested delay before retrying.
retry_after: Duration,
},
/// A handler-level error occurred.
Actor(crate::actor::ActorError),
/// The operation was cancelled via CancellationToken.
Cancelled,
/// The requested capability is not supported by this adapter.
NotSupported(NotSupportedError),
/// Actor spawn failed.
SpawnFailed(String),
}
impl fmt::Display for RuntimeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Send(e) => write!(f, "send error: {}", e),
Self::ActorNotFound(id) => write!(f, "actor not found: {}", id),
Self::Timeout => write!(f, "operation timed out"),
Self::Rejected {
interceptor,
reason,
} => {
write!(f, "rejected by '{}': {}", interceptor, reason)
}
Self::RetryAfter {
interceptor,
retry_after,
} => {
write!(
f,
"retry after {:?} (suggested by '{}')",
retry_after, interceptor
)
}
Self::Actor(e) => write!(f, "actor error: {}", e),
Self::Cancelled => write!(f, "operation cancelled"),
Self::NotSupported(e) => write!(f, "{}", e),
Self::SpawnFailed(msg) => write!(f, "spawn failed: {}", msg),
}
}
}
impl std::error::Error for RuntimeError {}
impl From<ActorSendError> for RuntimeError {
fn from(e: ActorSendError) -> Self {
Self::Send(e)
}
}