1use std::borrow::Cow;
4use std::net::SocketAddr;
5use std::path::PathBuf;
6
7use aion::EngineError;
8use aion_core::{ActivityId, WorkflowId};
9use aion_proto::WireError;
10use aion_store::StoreError;
11use thiserror::Error;
12
13#[path = "error_engine.rs"]
14mod engine;
15#[path = "error_process_exit.rs"]
16mod process_exit;
17
18#[derive(Debug, Error)]
20pub enum ServerError {
21 #[error("configuration error: {message}")]
23 Config {
24 message: String,
26 },
27
28 #[error(
30 "unsafe store.data_dir `{}`: ancestor `{}` is not owner-controlled: {reason}; \
31 leave store.data_dir unset so it defaults beneath the private Aion home \
32 (`$AION_HOME`, default `$HOME/.aion`), or set a path whose ancestor chain is \
33 owner-only (a leading `~` expands against $HOME; a relative path resolves \
34 against the server's working directory)",
35 .data_root.display(),
36 .component.display()
37 )]
38 UnsafeDataRootAncestor {
39 data_root: PathBuf,
41 component: PathBuf,
43 reason: String,
45 },
46
47 #[error("{transport} transport failed at {address}: {message}")]
49 TransportBind {
50 transport: &'static str,
52 address: SocketAddr,
54 message: String,
56 },
57
58 #[error("{transport} transport task failed: {message}")]
60 Transport {
61 transport: &'static str,
63 message: String,
65 },
66
67 #[error("{listener} listener failed: {message}")]
69 SignalListener {
70 listener: &'static str,
72 message: String,
74 },
75
76 #[error("death note error: {message}")]
79 DeathNote {
80 message: String,
82 },
83
84 #[error("pid file error: {message}")]
86 PidFile {
87 message: String,
89 },
90
91 #[error("incarnation identity error: {message}")]
94 Incarnation {
95 message: String,
97 },
98
99 #[error("namespace error: {message}")]
101 Namespace {
102 message: String,
104 },
105
106 #[error("engine call failed: {source}")]
108 EngineCall {
109 #[from]
111 source: EngineError,
112 },
113
114 #[error("store backend failed: {source}")]
116 StoreBackend {
117 #[from]
119 source: StoreError,
120 },
121
122 #[error("stream failure: {failure}")]
124 Stream {
125 failure: StreamFailure,
127 },
128
129 #[error(
131 "worker dispatch failed for namespace {namespace}, activity type {activity_type}: {reason}"
132 )]
133 WorkerDispatch {
134 namespace: String,
136 activity_type: String,
138 reason: String,
140 },
141
142 #[error("worker connection lost during dispatch on {channel}: {detail}")]
155 WorkerConnectionLost {
156 channel: String,
158 detail: String,
160 },
161
162 #[error("worker connection busy during dispatch on {channel}: {detail}")]
173 WorkerBusy {
174 channel: String,
176 detail: String,
178 },
179
180 #[error(
183 "pending activity collision for workflow {workflow_id}, activity {activity_id}: \
184 a live responder already owns this execution site"
185 )]
186 PendingActivityCollision {
187 workflow_id: WorkflowId,
189 activity_id: ActivityId,
191 },
192
193 #[error(
196 "activity completion rejected for workflow {workflow_id}, activity {activity_id}: {reason}"
197 )]
198 ActivityCompletionRejected {
199 workflow_id: WorkflowId,
201 activity_id: ActivityId,
203 reason: CompletionRejectionReason,
205 },
206
207 #[error(
218 "declared command for workflow {workflow_id}, activity {activity_id} attempt {attempt} \
219 is already executing at this server"
220 )]
221 DeclaredAttemptCollision {
222 workflow_id: WorkflowId,
224 activity_id: ActivityId,
226 attempt: u32,
228 },
229
230 #[error(
240 "declared command for workflow {workflow_id}, activity {activity_id} attempt {attempt} \
241 refused: this server is draining and starts no new work"
242 )]
243 DrainingRefusedDeclaredAttempt {
244 workflow_id: WorkflowId,
246 activity_id: ActivityId,
248 attempt: u32,
250 },
251
252 #[error("{resource} lock was poisoned")]
254 LockPoisoned {
255 resource: &'static str,
257 },
258
259 #[error("wire error: {wire}")]
261 Wire {
262 wire: WireError,
264 },
265}
266
267#[derive(Clone, Copy, Debug, Eq, Error, PartialEq)]
269pub enum CompletionRejectionReason {
270 #[error("completion token is missing (worker registration era is incompatible)")]
272 MissingCompletionToken,
273 #[error("no execution generation is currently accepting completion")]
275 NoCurrentGeneration,
276 #[error("completion token belongs to a stale execution generation")]
278 StaleGeneration,
279}
280
281#[derive(Clone, Copy, Debug, Eq, Error, PartialEq)]
283pub enum StreamFailure {
284 #[error("consumer lagged behind bounded buffer")]
286 Lagged,
287 #[error("subscriber connection closed")]
289 Closed,
290 #[error("engine event stream closed")]
292 UpstreamClosed,
293}
294
295impl From<WireError> for ServerError {
296 fn from(wire: WireError) -> Self {
297 Self::Wire { wire }
298 }
299}
300
301impl ServerError {
302 #[must_use]
305 pub fn to_wire_error(&self) -> WireError {
306 match self {
307 Self::Config { .. }
308 | Self::UnsafeDataRootAncestor { .. }
309 | Self::TransportBind { .. }
310 | Self::Transport { .. }
311 | Self::SignalListener { .. }
312 | Self::DeathNote { .. }
313 | Self::PidFile { .. }
314 | Self::Incarnation { .. }
315 | Self::LockPoisoned { .. } => WireError::backend("server backend failure"),
316 Self::ActivityCompletionRejected { .. } => {
317 WireError::backend("stale activity completion rejected")
318 }
319 Self::PendingActivityCollision { .. } => {
320 WireError::backend("pending activity collision")
321 }
322 Self::DeclaredAttemptCollision { .. } => {
323 WireError::backend("declared command attempt collision")
324 }
325 Self::DrainingRefusedDeclaredAttempt { .. } => {
326 WireError::backend("declared command refused: server draining")
327 }
328 Self::WorkerDispatch { .. } => WireError::backend("worker dispatch failed"),
329 Self::WorkerConnectionLost { .. } => {
330 WireError::backend("worker connection lost during dispatch")
331 }
332 Self::WorkerBusy { .. } => WireError::backend("worker connection busy during dispatch"),
333 Self::Namespace { message } => WireError::namespace_denied(message.clone()),
334 Self::EngineCall { source } => wire_from_engine(source),
335 Self::StoreBackend { source } => wire_from_store(source),
336 Self::Stream { failure } => match failure {
337 StreamFailure::Lagged => WireError::lagged("subscriber lagged behind"),
338 StreamFailure::Closed | StreamFailure::UpstreamClosed => {
339 WireError::backend("event stream closed")
340 }
341 },
342 Self::Wire { wire } => wire.clone(),
343 }
344 }
345
346 #[must_use]
348 pub const fn is_config(&self) -> bool {
349 matches!(
350 self,
351 Self::Config { .. } | Self::UnsafeDataRootAncestor { .. }
352 )
353 }
354
355 #[must_use]
357 pub fn namespace_denied(message: impl Into<String>) -> Self {
358 Self::Namespace {
359 message: message.into(),
360 }
361 }
362
363 #[must_use]
371 pub fn placement_admission_denied(
372 namespace: &str,
373 worker_node: Option<&str>,
374 required: &std::collections::BTreeSet<String>,
375 ) -> Self {
376 let node = worker_node.unwrap_or("none");
377 let required = required
378 .iter()
379 .map(String::as_str)
380 .collect::<Vec<_>>()
381 .join(", ");
382 Self::namespace_denied(format!(
383 "worker registration rejected: namespace {namespace} is Pinned to node label(s) \
384 [{required}] but the worker advertises node {node}, which is not in the required set"
385 ))
386 }
387
388 #[must_use]
391 pub fn deploy_denied(message: impl Into<String>) -> Self {
392 Self::Wire {
393 wire: WireError::deploy_denied(message),
394 }
395 }
396
397 #[must_use]
399 pub const fn lagged_stream() -> Self {
400 Self::Stream {
401 failure: StreamFailure::Lagged,
402 }
403 }
404
405 #[must_use]
407 pub fn worker_dispatch(
408 namespace: impl Into<String>,
409 activity_type: impl Into<String>,
410 reason: impl Into<String>,
411 ) -> Self {
412 Self::WorkerDispatch {
413 namespace: namespace.into(),
414 activity_type: activity_type.into(),
415 reason: reason.into(),
416 }
417 }
418
419 #[must_use]
422 pub fn worker_connection_lost(channel: impl Into<String>, detail: impl Into<String>) -> Self {
423 Self::WorkerConnectionLost {
424 channel: channel.into(),
425 detail: detail.into(),
426 }
427 }
428
429 #[must_use]
435 pub const fn is_worker_connection_lost(&self) -> bool {
436 matches!(self, Self::WorkerConnectionLost { .. })
437 }
438
439 #[must_use]
442 pub fn worker_busy(channel: impl Into<String>, detail: impl Into<String>) -> Self {
443 Self::WorkerBusy {
444 channel: channel.into(),
445 detail: detail.into(),
446 }
447 }
448
449 #[must_use]
456 pub const fn is_worker_busy(&self) -> bool {
457 matches!(self, Self::WorkerBusy { .. })
458 }
459
460 #[must_use]
462 pub const fn lock_poisoned(resource: &'static str) -> Self {
463 Self::LockPoisoned { resource }
464 }
465}
466
467#[derive(Clone)]
469pub struct ErrorTraceFields<'a> {
470 pub error_type: Cow<'a, str>,
472 pub store_error_type: Option<&'static str>,
474 pub reason: &'a dyn std::fmt::Display,
476}
477
478impl<'a> ErrorTraceFields<'a> {
479 fn plain(error_type: &'static str, reason: &'a dyn std::fmt::Display) -> Self {
481 Self {
482 error_type: Cow::Borrowed(error_type),
483 store_error_type: None,
484 reason,
485 }
486 }
487}
488
489impl ServerError {
490 #[must_use]
492 pub fn trace_fields(&self) -> ErrorTraceFields<'_> {
493 match self {
494 Self::Config { message } => ErrorTraceFields::plain("Config", message),
495 Self::UnsafeDataRootAncestor { reason, .. } => {
496 ErrorTraceFields::plain("UnsafeDataRootAncestor", reason)
497 }
498 Self::TransportBind { message, .. } => {
499 ErrorTraceFields::plain("TransportBind", message)
500 }
501 Self::Transport { message, .. } => ErrorTraceFields::plain("Transport", message),
502 Self::SignalListener { message, .. } => {
503 ErrorTraceFields::plain("SignalListener", message)
504 }
505 Self::PidFile { message } => ErrorTraceFields::plain("PidFile", message),
506 Self::Incarnation { message } => ErrorTraceFields::plain("Incarnation", message),
507 Self::DeathNote { message } => ErrorTraceFields::plain("DeathNote", message),
508 Self::Namespace { message } => ErrorTraceFields::plain("Namespace", message),
509 Self::EngineCall { source } => engine_trace_fields(source),
510 Self::StoreBackend { source } => store_trace_fields(source),
511 Self::Stream { failure } => ErrorTraceFields::plain("Stream", failure),
512 Self::WorkerDispatch { reason, .. } => {
513 ErrorTraceFields::plain("WorkerDispatch", reason)
514 }
515 Self::WorkerConnectionLost { detail, .. } => {
516 ErrorTraceFields::plain("WorkerConnectionLost", detail)
517 }
518 Self::WorkerBusy { detail, .. } => ErrorTraceFields::plain("WorkerBusy", detail),
519 Self::PendingActivityCollision { activity_id, .. } => {
520 ErrorTraceFields::plain("PendingActivityCollision", activity_id)
521 }
522 Self::DeclaredAttemptCollision { activity_id, .. } => {
523 ErrorTraceFields::plain("DeclaredAttemptCollision", activity_id)
524 }
525 Self::DrainingRefusedDeclaredAttempt { activity_id, .. } => {
526 ErrorTraceFields::plain("DrainingRefusedDeclaredAttempt", activity_id)
527 }
528 Self::ActivityCompletionRejected { reason, .. } => {
529 ErrorTraceFields::plain("ActivityCompletionRejected", reason)
530 }
531 Self::LockPoisoned { resource } => ErrorTraceFields::plain("LockPoisoned", resource),
532 Self::Wire { wire } => ErrorTraceFields {
533 error_type: wire
534 .error_type
535 .as_deref()
536 .map_or_else(|| Cow::Borrowed(wire.code.as_str()), Cow::Borrowed),
537 store_error_type: None,
538 reason: wire,
539 },
540 }
541 }
542}
543
544fn never_alive_error_type(source: &EngineError) -> &'static str {
556 match source {
557 EngineError::TerminalWriterUnavailable { .. } => "TerminalWriterUnavailable",
558 EngineError::TerminalWriterHeld { .. } => "TerminalWriterHeld",
559 EngineError::WorkflowWriterHeld { .. } => "WorkflowWriterHeld",
560 EngineError::RunIsRecoverable { .. } => "RunIsRecoverable",
561 EngineError::NoResidencyVerdict { .. } => "NoResidencyVerdict",
562 _ => "EngineError",
563 }
564}
565
566fn durability_trace_fields<'a>(
572 durability: &'a aion::durability::DurabilityError,
573 source: &'a EngineError,
574) -> ErrorTraceFields<'a> {
575 match durability {
576 aion::durability::DurabilityError::Store(store) => store_trace_fields(store),
577 aion::durability::DurabilityError::NonDeterminism(_)
578 | aion::durability::DurabilityError::HistoryShape { .. }
579 | aion::durability::DurabilityError::SearchAttribute(_) => {
580 simple_engine_fields("Durability", source)
581 }
582 aion::durability::DurabilityError::EngineTaskEpochClosed { .. } => {
588 simple_engine_fields("EngineTaskEpochClosed", source)
589 }
590 }
591}
592
593fn engine_trace_fields(source: &EngineError) -> ErrorTraceFields<'_> {
594 match source {
595 EngineError::WorkflowNotFound { .. } => simple_engine_fields("WorkflowNotFound", source),
596 EngineError::TerminalWriterUnavailable { .. }
598 | EngineError::TerminalWriterHeld { .. }
599 | EngineError::WorkflowWriterHeld { .. }
602 | EngineError::RunIsRecoverable { .. }
603 | EngineError::NoResidencyVerdict { .. } => {
604 simple_engine_fields(never_alive_error_type(source), source)
605 }
606 EngineError::InvalidState { .. } => simple_engine_fields("InvalidState", source),
607 EngineError::ScheduleNotFound { .. } => simple_engine_fields("ScheduleNotFound", source),
608 EngineError::ShuttingDown => simple_engine_fields("ShuttingDown", source),
609 EngineError::EngineTaskEpochClosed { .. } => {
610 simple_engine_fields("EngineTaskEpochClosed", source)
611 }
612 EngineError::Store(store) => store_trace_fields(store),
613 EngineError::Durability(durability) => durability_trace_fields(durability, source),
614 EngineError::MissingStore => simple_engine_fields("MissingStore", source),
615 EngineError::MissingVisibilityStore => {
616 simple_engine_fields("MissingVisibilityStore", source)
617 }
618 EngineError::ConflictingEventPublisher => {
619 simple_engine_fields("ConflictingEventPublisher", source)
620 }
621 EngineError::EventStreaming(_) => simple_engine_fields("EventStreaming", source),
622 EngineError::Load { .. } => simple_engine_fields("Load", source),
623 EngineError::UnenforceableContract { .. } => {
624 simple_engine_fields("UnenforceableContract", source)
625 }
626 EngineError::UnknownVersion { .. } => simple_engine_fields("UnknownVersion", source),
627 EngineError::VersionPinned { .. } => simple_engine_fields("VersionPinned", source),
628 EngineError::RouteActive { .. } => simple_engine_fields("RouteActive", source),
629 EngineError::ManifestMismatch { .. } => simple_engine_fields("ManifestMismatch", source),
630 EngineError::Package(_) => simple_engine_fields("Package", source),
631 EngineError::ContractIdentity { .. } => simple_engine_fields("ContractIdentity", source),
632 EngineError::NoQueueDeclaration { .. } => {
633 simple_engine_fields("NoQueueDeclaration", source)
634 }
635 EngineError::StartInputRefused { .. } => simple_engine_fields("StartInputRefused", source),
636 EngineError::SignalRefused { .. } => simple_engine_fields("SignalRefused", source),
637 EngineError::Schedule { .. } => simple_engine_fields("Schedule", source),
638 EngineError::Runtime { .. } => simple_engine_fields("Runtime", source),
639 EngineError::Gate3BifReplacementMissing { .. } => {
640 simple_engine_fields("Gate3BifReplacementMissing", source)
641 }
642 EngineError::StartupRecoveryNotDeferred => {
643 simple_engine_fields("StartupRecoveryNotDeferred", source)
644 }
645 EngineError::StartupRecoveryAlreadyRan => {
646 simple_engine_fields("StartupRecoveryAlreadyRan", source)
647 }
648 EngineError::StartupCatchupBeforeWorkflowRecovery => {
649 simple_engine_fields("StartupCatchupBeforeWorkflowRecovery", source)
650 }
651 EngineError::StartupRecoverySlotPoisoned => {
652 simple_engine_fields("StartupRecoverySlotPoisoned", source)
653 }
654 EngineError::CleanupExecutorPoisoned => {
655 simple_engine_fields("CleanupExecutorPoisoned", source)
656 }
657 EngineError::CleanupExecutorShutdownTimedOut { .. } => {
658 simple_engine_fields("CleanupExecutorShutdownTimedOut", source)
659 }
660 EngineError::RunNotInHistory { .. } => simple_engine_fields("RunNotInHistory", source),
661 EngineError::ProcessExitRegistryPoisoned => {
662 simple_engine_fields("ProcessExitRegistryPoisoned", source)
663 }
664 EngineError::ProcessExitOwnershipPoisoned { .. } => {
665 simple_engine_fields("ProcessExitOwnershipPoisoned", source)
666 }
667 EngineError::ProcessExitStatePoisoned { .. }
668 | EngineError::ProcessExitSubscriptionUnavailable
669 | EngineError::ProcessExitDrainerSpawn { .. }
670 | EngineError::ProcessExitDrainerPoisoned
671 | EngineError::ProcessExitOutcomeMissingAfterEvent { .. }
672 | EngineError::ProcessExitEventStreamDisconnected
673 | EngineError::ProcessExitDrainerShutdownTimedOut { .. }
674 | EngineError::ProcessExitDrainerPanicked => process_exit::drainer_trace(source),
675 EngineError::ProcessExitCallbackDispatcherPoisoned
676 | EngineError::ProcessExitCallbackDispatcherUnavailable
677 | EngineError::ProcessExitCallbackDispatcherShutdownTimedOut { .. } => {
678 process_exit::callback_trace(source)
679 }
680 EngineError::ProcessExitAlreadyTerminal { .. } => {
681 simple_engine_fields("ProcessExitAlreadyTerminal", source)
682 }
683 EngineError::ActivityDeliveryPoisoned { .. } => {
684 simple_engine_fields("ActivityDeliveryPoisoned", source)
685 }
686 EngineError::RegistryPoisoned => simple_engine_fields("RegistryPoisoned", source),
687 EngineError::CatalogPoisoned => simple_engine_fields("CatalogPoisoned", source),
688 EngineError::NifRegistration { .. } => simple_engine_fields("NifRegistration", source),
689 EngineError::SignalRouter(_) => simple_engine_fields("SignalRouter", source),
690 EngineError::Query(query) => simple_engine_fields(engine::query_error_type(query), source),
691 }
692}
693
694fn simple_engine_fields<'a>(
695 error_type: &'static str,
696 source: &'a EngineError,
697) -> ErrorTraceFields<'a> {
698 ErrorTraceFields {
699 error_type: Cow::Borrowed(error_type),
700 store_error_type: None,
701 reason: source,
702 }
703}
704
705fn store_trace_fields(source: &StoreError) -> ErrorTraceFields<'_> {
706 ErrorTraceFields {
707 error_type: Cow::Borrowed("StoreError"),
708 store_error_type: Some(engine::store_error_type(source)),
709 reason: source,
710 }
711}
712
713fn wire_from_engine(source: &EngineError) -> WireError {
714 use EngineError as E;
715 use engine::backend_wire as backend;
716
717 match source {
718 EngineError::WorkflowNotFound { .. } => {
719 WireError::not_found_with_type("WorkflowNotFound", source.to_string())
720 }
721 EngineError::InvalidState { reason } => engine::invalid_state_wire(reason),
723 E::TerminalWriterUnavailable { .. }
729 | E::TerminalWriterHeld { .. }
730 | E::WorkflowWriterHeld { .. }
734 | E::RunIsRecoverable { .. }
735 | E::NoResidencyVerdict { .. } => engine::invalid_state_wire(&source.to_string())
736 .with_error_type(never_alive_error_type(source)),
737 EngineError::ScheduleNotFound { .. } => {
738 WireError::not_found_with_type("ScheduleNotFound", source.to_string())
739 }
740 EngineError::ShuttingDown => {
741 WireError::not_running_with_type("ShuttingDown", source.to_string())
742 }
743 E::EngineTaskEpochClosed { .. } => backend("EngineTaskEpochClosed", source),
764 EngineError::Store(store) => wire_from_store(store),
765 EngineError::Durability(durability) => engine::durability_wire(durability, source),
766 E::MissingStore => backend("MissingStore", source),
767 E::MissingVisibilityStore => backend("MissingVisibilityStore", source),
768 E::ConflictingEventPublisher => backend("ConflictingEventPublisher", source),
769 E::EventStreaming(_) => backend("EventStreaming", source),
770 E::Load { .. } => backend("Load", source),
771 EngineError::UnenforceableContract { .. } => {
774 WireError::invalid_input(source.to_string()).with_error_type("UnenforceableContract")
775 }
776 EngineError::UnknownVersion { .. } => {
778 WireError::not_found_with_type("UnknownVersion", source.to_string())
779 }
780 EngineError::VersionPinned { .. } => {
781 WireError::version_pinned(source.to_string()).with_error_type("VersionPinned")
782 }
783 EngineError::RouteActive { .. } => {
784 WireError::version_pinned(source.to_string()).with_error_type("RouteActive")
785 }
786 EngineError::ManifestMismatch { .. } => {
787 WireError::invalid_input(source.to_string()).with_error_type("ManifestMismatch")
788 }
789 E::Package(_) => backend("Package", source),
790 E::ContractIdentity { .. } => engine::contract_refusal_wire("ContractIdentity", source),
791 E::NoQueueDeclaration { .. } => engine::contract_refusal_wire("NoQueueDeclaration", source),
792 E::StartInputRefused { .. } => engine::declared_contract_wire("StartInputRefused", source),
793 E::SignalRefused { .. } => engine::declared_contract_wire("SignalRefused", source),
794 EngineError::Schedule { .. } => backend("Schedule", source),
795 E::Runtime { .. } => backend("Runtime", source),
796 E::Gate3BifReplacementMissing { .. } => backend("Gate3BifReplacementMissing", source),
797 E::StartupRecoveryNotDeferred => backend("StartupRecoveryNotDeferred", source),
800 E::StartupRecoveryAlreadyRan => backend("StartupRecoveryAlreadyRan", source),
801 E::StartupCatchupBeforeWorkflowRecovery => {
802 backend("StartupCatchupBeforeWorkflowRecovery", source)
803 }
804 E::StartupRecoverySlotPoisoned => backend("StartupRecoverySlotPoisoned", source),
805 E::CleanupExecutorPoisoned => backend("CleanupExecutorPoisoned", source),
806 E::CleanupExecutorShutdownTimedOut { .. } => {
807 backend("CleanupExecutorShutdownTimedOut", source)
808 }
809 E::RunNotInHistory { .. } => backend("RunNotInHistory", source),
815 E::ProcessExitRegistryPoisoned => backend("ProcessExitRegistryPoisoned", source),
816 E::ProcessExitOwnershipPoisoned { .. } => backend("ProcessExitOwnershipPoisoned", source),
817 EngineError::ProcessExitStatePoisoned { .. }
818 | EngineError::ProcessExitSubscriptionUnavailable
819 | EngineError::ProcessExitDrainerSpawn { .. }
820 | EngineError::ProcessExitDrainerPoisoned
821 | EngineError::ProcessExitOutcomeMissingAfterEvent { .. }
822 | EngineError::ProcessExitEventStreamDisconnected
823 | EngineError::ProcessExitDrainerShutdownTimedOut { .. }
824 | EngineError::ProcessExitDrainerPanicked => process_exit::drainer_wire(source),
825 EngineError::ProcessExitCallbackDispatcherPoisoned
826 | EngineError::ProcessExitCallbackDispatcherUnavailable
827 | EngineError::ProcessExitCallbackDispatcherShutdownTimedOut { .. } => {
828 process_exit::callback_wire(source)
829 }
830 E::ProcessExitAlreadyTerminal { .. } => backend("ProcessExitAlreadyTerminal", source),
831 E::ActivityDeliveryPoisoned { .. } => backend("ActivityDeliveryPoisoned", source),
832 E::CatalogPoisoned => backend("CatalogPoisoned", source),
833 E::RegistryPoisoned => backend("RegistryPoisoned", source),
834 E::NifRegistration { .. } => backend("NifRegistration", source),
835 E::SignalRouter(_) => backend("SignalRouter", source),
836 EngineError::Query(query) => engine::query_wire(query, source),
837 }
838}
839
840fn wire_from_store(source: &StoreError) -> WireError {
841 match source {
842 StoreError::SequenceConflict { .. } => WireError::new_with_type(
843 aion_proto::WireErrorCode::SequenceConflict,
844 "SequenceConflict",
845 source.to_string(),
846 ),
847 StoreError::NotFound { .. } => {
848 WireError::not_found_with_type("NotFound", source.to_string())
849 }
850 StoreError::NotOwner { .. } => {
851 WireError::not_owner(source.to_string()).with_error_type("NotOwner")
852 }
853 StoreError::Backend(_) => WireError::backend_with_type("Backend", source.to_string()),
854 StoreError::Serialization(_) => {
855 WireError::backend_with_type("Serialization", source.to_string())
856 }
857 }
858}
859
860#[cfg(test)]
861#[path = "error_tests.rs"]
862mod tests;