1use hataori_runtime_foundation::{
2 protocol::{ActionId, DomainId, LocalityId, ObjectId, ObjectLocation, ObjectTypeId, RequestId},
3 transport::TransportError,
4};
5use std::{fmt, time::Duration};
6
7pub const MAX_ERROR_BYTES: usize = 4096;
8
9#[derive(Clone, Copy, Debug, Eq, PartialEq)]
10pub enum RuntimeState {
11 Created,
12 Bootstrapping,
13 Running,
14 Draining,
15 Stopped,
16 Failed,
17}
18
19#[derive(Clone, Copy, Debug, Eq, PartialEq)]
20pub enum ResourceKind {
21 PendingCalls,
22 ActionQueue,
23 DedupEntries,
24 DedupBytes,
25 SendTickets,
26 Objects,
27 ObjectMailbox,
28 ResolverEntries,
29 LocalityLeases,
30 ObjectRoots,
31 PlacementTickets,
32 LeaseTransfers,
33 Migrations,
34 PreparedMigrations,
35 Forwarders,
36 SnapshotBytes,
37 SnapshotSegments,
38}
39
40#[derive(Clone, Debug, Eq, PartialEq)]
41pub enum ActionError {
42 Codec(String),
43 User(String),
44 Panic,
45}
46
47impl ActionError {
48 pub fn codec(message: impl Into<String>) -> Self {
49 Self::Codec(cap(message.into()))
50 }
51
52 pub fn user(message: impl Into<String>) -> Self {
53 Self::User(cap(message.into()))
54 }
55
56 pub(crate) fn message(&self) -> String {
57 match self {
58 Self::Codec(message) | Self::User(message) => message.clone(),
59 Self::Panic => "action handler panicked".into(),
60 }
61 }
62}
63
64impl fmt::Display for ActionError {
65 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
66 write!(formatter, "action error: {self:?}")
67 }
68}
69
70impl std::error::Error for ActionError {}
71
72#[derive(Clone, Debug, Eq, PartialEq)]
73pub enum RuntimeError {
74 InvalidLimits(&'static str),
75 BuilderSealed,
76 HandshakeNotPrepared,
77 InvalidState {
78 expected: RuntimeState,
79 actual: RuntimeState,
80 },
81 DuplicateAction(ActionId),
82 UnknownAction(ActionId),
83 UnknownDomain(DomainId),
84 DuplicateObjectType(ObjectTypeId),
85 UnknownObjectType(ObjectTypeId),
86 UnknownObject(ObjectId),
87 ObjectCollected(ObjectId),
88 StaleObjectLocation(ObjectId),
89 ObjectAction(String),
90 InvalidObjectTypeId,
91 InvalidObjectConcurrency,
92 PinnedObjectType(ObjectTypeId),
93 MigrationInProgress(ObjectId),
94 MigrationConflict(ObjectId),
95 Migration {
96 request: RequestId,
97 message: String,
98 },
99 MigrationRolledBack(ObjectId),
100 MigrationCommittedFailure {
101 object: ObjectId,
102 message: String,
103 },
104 SnapshotTooLarge {
105 bytes: usize,
106 limit: usize,
107 },
108 Moved {
109 object: ObjectId,
110 location: ObjectLocation,
111 },
112 RedirectLimit(ObjectId),
113 InvalidActionId,
114 InvalidSchema,
115 InvalidDeadline,
116 InvalidMembership(LocalityId),
117 ResourceExhausted {
118 resource: ResourceKind,
119 limit: usize,
120 },
121 DeadlineExceeded {
122 request: RequestId,
123 deadline: Duration,
124 },
125 Cancelled(RequestId),
126 RemoteAction {
127 request: RequestId,
128 message: String,
129 },
130 RemoteObject {
131 request: RequestId,
132 message: String,
133 },
134 Placement {
135 request: RequestId,
136 message: String,
137 },
138 Lease {
139 request: RequestId,
140 message: String,
141 },
142 LeaseTransferExpired(ObjectId),
143 DuplicateResultUnavailable(RequestId),
144 Protocol(String),
145 Transport(TransportError),
146 PeerFailed(LocalityId),
147 Shutdown,
148 ShutdownTimeout,
149 RetainedResources,
150}
151
152impl fmt::Display for RuntimeError {
153 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
154 write!(formatter, "runtime error: {self:?}")
155 }
156}
157
158impl std::error::Error for RuntimeError {}
159
160impl From<TransportError> for RuntimeError {
161 fn from(error: TransportError) -> Self {
162 Self::Transport(error)
163 }
164}
165
166pub(crate) fn cap(mut message: String) -> String {
167 if message.len() <= MAX_ERROR_BYTES {
168 return message;
169 }
170 let mut end = MAX_ERROR_BYTES;
171 while !message.is_char_boundary(end) {
172 end -= 1;
173 }
174 message.truncate(end);
175 message
176}