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(transparent)]
97 HomeAlreadyClaimed {
98 refusal: Box<crate::control::claim::HomeAlreadyClaimed>,
102 },
103
104 #[error("incarnation identity error: {message}")]
107 Incarnation {
108 message: String,
110 },
111
112 #[error("namespace error: {message}")]
114 Namespace {
115 message: String,
117 },
118
119 #[error("engine call failed: {source}")]
121 EngineCall {
122 #[from]
124 source: EngineError,
125 },
126
127 #[error("store backend failed: {source}")]
129 StoreBackend {
130 #[from]
132 source: StoreError,
133 },
134
135 #[error("stream failure: {failure}")]
137 Stream {
138 failure: StreamFailure,
140 },
141
142 #[error(
144 "worker dispatch failed for namespace {namespace}, activity type {activity_type}: {reason}"
145 )]
146 WorkerDispatch {
147 namespace: String,
149 activity_type: String,
151 reason: String,
153 },
154
155 #[error("worker connection lost during dispatch on {channel}: {detail}")]
168 WorkerConnectionLost {
169 channel: String,
171 detail: String,
173 },
174
175 #[error("worker connection busy during dispatch on {channel}: {detail}")]
186 WorkerBusy {
187 channel: String,
189 detail: String,
191 },
192
193 #[error(
196 "pending activity collision for workflow {workflow_id}, activity {activity_id}: \
197 a live responder already owns this execution site"
198 )]
199 PendingActivityCollision {
200 workflow_id: WorkflowId,
202 activity_id: ActivityId,
204 },
205
206 #[error(
209 "activity completion rejected for workflow {workflow_id}, activity {activity_id}: {reason}"
210 )]
211 ActivityCompletionRejected {
212 workflow_id: WorkflowId,
214 activity_id: ActivityId,
216 reason: CompletionRejectionReason,
218 },
219
220 #[error(
231 "declared command for workflow {workflow_id}, activity {activity_id} attempt {attempt} \
232 is already executing at this server"
233 )]
234 DeclaredAttemptCollision {
235 workflow_id: WorkflowId,
237 activity_id: ActivityId,
239 attempt: u32,
241 },
242
243 #[error(
253 "declared command for workflow {workflow_id}, activity {activity_id} attempt {attempt} \
254 refused: this server is draining and starts no new work"
255 )]
256 DrainingRefusedDeclaredAttempt {
257 workflow_id: WorkflowId,
259 activity_id: ActivityId,
261 attempt: u32,
263 },
264
265 #[error("{resource} lock was poisoned")]
267 LockPoisoned {
268 resource: &'static str,
270 },
271
272 #[error("wire error: {wire}")]
274 Wire {
275 wire: WireError,
277 },
278}
279
280#[derive(Clone, Copy, Debug, Eq, Error, PartialEq)]
282pub enum CompletionRejectionReason {
283 #[error("completion token is missing (worker registration era is incompatible)")]
285 MissingCompletionToken,
286 #[error("no execution generation is currently accepting completion")]
288 NoCurrentGeneration,
289 #[error("completion token belongs to a stale execution generation")]
291 StaleGeneration,
292}
293
294#[derive(Clone, Copy, Debug, Eq, Error, PartialEq)]
296pub enum StreamFailure {
297 #[error("consumer lagged behind bounded buffer")]
299 Lagged,
300 #[error("subscriber connection closed")]
302 Closed,
303 #[error("engine event stream closed")]
305 UpstreamClosed,
306}
307
308impl From<WireError> for ServerError {
309 fn from(wire: WireError) -> Self {
310 Self::Wire { wire }
311 }
312}
313
314impl ServerError {
315 #[must_use]
318 pub fn to_wire_error(&self) -> WireError {
319 match self {
320 Self::Config { .. }
321 | Self::UnsafeDataRootAncestor { .. }
322 | Self::TransportBind { .. }
323 | Self::Transport { .. }
324 | Self::SignalListener { .. }
325 | Self::DeathNote { .. }
326 | Self::PidFile { .. }
327 | Self::HomeAlreadyClaimed { .. }
328 | Self::Incarnation { .. }
329 | Self::LockPoisoned { .. } => WireError::backend("server backend failure"),
330 Self::ActivityCompletionRejected { .. } => {
331 WireError::backend("stale activity completion rejected")
332 }
333 Self::PendingActivityCollision { .. } => {
334 WireError::backend("pending activity collision")
335 }
336 Self::DeclaredAttemptCollision { .. } => {
337 WireError::backend("declared command attempt collision")
338 }
339 Self::DrainingRefusedDeclaredAttempt { .. } => {
340 WireError::backend("declared command refused: server draining")
341 }
342 Self::WorkerDispatch { .. } => WireError::backend("worker dispatch failed"),
343 Self::WorkerConnectionLost { .. } => {
344 WireError::backend("worker connection lost during dispatch")
345 }
346 Self::WorkerBusy { .. } => WireError::backend("worker connection busy during dispatch"),
347 Self::Namespace { message } => WireError::namespace_denied(message.clone()),
348 Self::EngineCall { source } => wire_from_engine(source),
349 Self::StoreBackend { source } => wire_from_store(source),
350 Self::Stream { failure } => match failure {
351 StreamFailure::Lagged => WireError::lagged("subscriber lagged behind"),
352 StreamFailure::Closed | StreamFailure::UpstreamClosed => {
353 WireError::backend("event stream closed")
354 }
355 },
356 Self::Wire { wire } => wire.clone(),
357 }
358 }
359
360 #[must_use]
362 pub const fn is_config(&self) -> bool {
363 matches!(
369 self,
370 Self::Config { .. }
371 | Self::UnsafeDataRootAncestor { .. }
372 | Self::HomeAlreadyClaimed { .. }
373 )
374 }
375
376 #[must_use]
378 pub fn namespace_denied(message: impl Into<String>) -> Self {
379 Self::Namespace {
380 message: message.into(),
381 }
382 }
383
384 #[must_use]
392 pub fn placement_admission_denied(
393 namespace: &str,
394 worker_node: Option<&str>,
395 required: &std::collections::BTreeSet<String>,
396 ) -> Self {
397 let node = worker_node.unwrap_or("none");
398 let required = required
399 .iter()
400 .map(String::as_str)
401 .collect::<Vec<_>>()
402 .join(", ");
403 Self::namespace_denied(format!(
404 "worker registration rejected: namespace {namespace} is Pinned to node label(s) \
405 [{required}] but the worker advertises node {node}, which is not in the required set"
406 ))
407 }
408
409 #[must_use]
412 pub fn deploy_denied(message: impl Into<String>) -> Self {
413 Self::Wire {
414 wire: WireError::deploy_denied(message),
415 }
416 }
417
418 #[must_use]
420 pub const fn lagged_stream() -> Self {
421 Self::Stream {
422 failure: StreamFailure::Lagged,
423 }
424 }
425
426 #[must_use]
428 pub fn worker_dispatch(
429 namespace: impl Into<String>,
430 activity_type: impl Into<String>,
431 reason: impl Into<String>,
432 ) -> Self {
433 Self::WorkerDispatch {
434 namespace: namespace.into(),
435 activity_type: activity_type.into(),
436 reason: reason.into(),
437 }
438 }
439
440 #[must_use]
443 pub fn worker_connection_lost(channel: impl Into<String>, detail: impl Into<String>) -> Self {
444 Self::WorkerConnectionLost {
445 channel: channel.into(),
446 detail: detail.into(),
447 }
448 }
449
450 #[must_use]
456 pub const fn is_worker_connection_lost(&self) -> bool {
457 matches!(self, Self::WorkerConnectionLost { .. })
458 }
459
460 #[must_use]
463 pub fn worker_busy(channel: impl Into<String>, detail: impl Into<String>) -> Self {
464 Self::WorkerBusy {
465 channel: channel.into(),
466 detail: detail.into(),
467 }
468 }
469
470 #[must_use]
477 pub const fn is_worker_busy(&self) -> bool {
478 matches!(self, Self::WorkerBusy { .. })
479 }
480
481 #[must_use]
483 pub const fn lock_poisoned(resource: &'static str) -> Self {
484 Self::LockPoisoned { resource }
485 }
486}
487
488#[derive(Clone)]
490pub struct ErrorTraceFields<'a> {
491 pub error_type: Cow<'a, str>,
493 pub store_error_type: Option<&'static str>,
495 pub reason: &'a dyn std::fmt::Display,
497}
498
499impl<'a> ErrorTraceFields<'a> {
500 fn plain(error_type: &'static str, reason: &'a dyn std::fmt::Display) -> Self {
502 Self {
503 error_type: Cow::Borrowed(error_type),
504 store_error_type: None,
505 reason,
506 }
507 }
508}
509
510impl ServerError {
511 #[must_use]
513 pub fn trace_fields(&self) -> ErrorTraceFields<'_> {
514 match self {
515 Self::Config { message } => ErrorTraceFields::plain("Config", message),
516 Self::UnsafeDataRootAncestor { reason, .. } => {
517 ErrorTraceFields::plain("UnsafeDataRootAncestor", reason)
518 }
519 Self::TransportBind { message, .. } => {
520 ErrorTraceFields::plain("TransportBind", message)
521 }
522 Self::Transport { message, .. } => ErrorTraceFields::plain("Transport", message),
523 Self::SignalListener { message, .. } => {
524 ErrorTraceFields::plain("SignalListener", message)
525 }
526 Self::PidFile { message } => ErrorTraceFields::plain("PidFile", message),
527 Self::HomeAlreadyClaimed { refusal } => {
528 ErrorTraceFields::plain("HomeAlreadyClaimed", refusal.as_ref())
529 }
530 Self::Incarnation { message } => ErrorTraceFields::plain("Incarnation", message),
531 Self::DeathNote { message } => ErrorTraceFields::plain("DeathNote", message),
532 Self::Namespace { message } => ErrorTraceFields::plain("Namespace", message),
533 Self::EngineCall { source } => engine_trace_fields(source),
534 Self::StoreBackend { source } => store_trace_fields(source),
535 Self::Stream { failure } => ErrorTraceFields::plain("Stream", failure),
536 Self::WorkerDispatch { reason, .. } => {
537 ErrorTraceFields::plain("WorkerDispatch", reason)
538 }
539 Self::WorkerConnectionLost { detail, .. } => {
540 ErrorTraceFields::plain("WorkerConnectionLost", detail)
541 }
542 Self::WorkerBusy { detail, .. } => ErrorTraceFields::plain("WorkerBusy", detail),
543 Self::PendingActivityCollision { activity_id, .. } => {
544 ErrorTraceFields::plain("PendingActivityCollision", activity_id)
545 }
546 Self::DeclaredAttemptCollision { activity_id, .. } => {
547 ErrorTraceFields::plain("DeclaredAttemptCollision", activity_id)
548 }
549 Self::DrainingRefusedDeclaredAttempt { activity_id, .. } => {
550 ErrorTraceFields::plain("DrainingRefusedDeclaredAttempt", activity_id)
551 }
552 Self::ActivityCompletionRejected { reason, .. } => {
553 ErrorTraceFields::plain("ActivityCompletionRejected", reason)
554 }
555 Self::LockPoisoned { resource } => ErrorTraceFields::plain("LockPoisoned", resource),
556 Self::Wire { wire } => ErrorTraceFields {
557 error_type: wire
558 .error_type
559 .as_deref()
560 .map_or_else(|| Cow::Borrowed(wire.code.as_str()), Cow::Borrowed),
561 store_error_type: None,
562 reason: wire,
563 },
564 }
565 }
566}
567
568fn never_alive_error_type(source: &EngineError) -> &'static str {
580 match source {
581 EngineError::TerminalWriterUnavailable { .. } => "TerminalWriterUnavailable",
582 EngineError::TerminalWriterHeld { .. } => "TerminalWriterHeld",
583 EngineError::WorkflowWriterHeld { .. } => "WorkflowWriterHeld",
584 EngineError::RunIsRecoverable { .. } => "RunIsRecoverable",
585 EngineError::NoResidencyVerdict { .. } => "NoResidencyVerdict",
586 _ => "EngineError",
587 }
588}
589
590fn durability_trace_fields<'a>(
596 durability: &'a aion::durability::DurabilityError,
597 source: &'a EngineError,
598) -> ErrorTraceFields<'a> {
599 match durability {
600 aion::durability::DurabilityError::Store(store) => store_trace_fields(store),
601 aion::durability::DurabilityError::NonDeterminism(_)
602 | aion::durability::DurabilityError::HistoryShape { .. }
603 | aion::durability::DurabilityError::SearchAttribute(_) => {
604 simple_engine_fields("Durability", source)
605 }
606 aion::durability::DurabilityError::EngineTaskEpochClosed { .. } => {
612 simple_engine_fields("EngineTaskEpochClosed", source)
613 }
614 }
615}
616
617fn engine_trace_fields(source: &EngineError) -> ErrorTraceFields<'_> {
618 match source {
619 EngineError::WorkflowNotFound { .. } => simple_engine_fields("WorkflowNotFound", source),
620 EngineError::TerminalWriterUnavailable { .. }
622 | EngineError::TerminalWriterHeld { .. }
623 | EngineError::WorkflowWriterHeld { .. }
626 | EngineError::RunIsRecoverable { .. }
627 | EngineError::NoResidencyVerdict { .. } => {
628 simple_engine_fields(never_alive_error_type(source), source)
629 }
630 EngineError::InvalidState { .. } => simple_engine_fields("InvalidState", source),
631 EngineError::ScheduleNotFound { .. } => simple_engine_fields("ScheduleNotFound", source),
632 EngineError::ShuttingDown => simple_engine_fields("ShuttingDown", source),
633 EngineError::EngineTaskEpochClosed { .. } => {
634 simple_engine_fields("EngineTaskEpochClosed", source)
635 }
636 EngineError::Store(store) => store_trace_fields(store),
637 EngineError::Durability(durability) => durability_trace_fields(durability, source),
638 EngineError::MissingStore => simple_engine_fields("MissingStore", source),
639 EngineError::MissingVisibilityStore => {
640 simple_engine_fields("MissingVisibilityStore", source)
641 }
642 EngineError::ConflictingEventPublisher => {
643 simple_engine_fields("ConflictingEventPublisher", source)
644 }
645 EngineError::EventStreaming(_) => simple_engine_fields("EventStreaming", source),
646 EngineError::Load { .. } => simple_engine_fields("Load", source),
647 EngineError::UnenforceableContract { .. } => {
648 simple_engine_fields("UnenforceableContract", source)
649 }
650 EngineError::UnknownVersion { .. } => simple_engine_fields("UnknownVersion", source),
651 EngineError::VersionPinned { .. } => simple_engine_fields("VersionPinned", source),
652 EngineError::RouteActive { .. } => simple_engine_fields("RouteActive", source),
653 EngineError::ManifestMismatch { .. } => simple_engine_fields("ManifestMismatch", source),
654 EngineError::Package(_) => simple_engine_fields("Package", source),
655 EngineError::ContractIdentity { .. } => simple_engine_fields("ContractIdentity", source),
656 EngineError::NoQueueDeclaration { .. } => {
657 simple_engine_fields("NoQueueDeclaration", source)
658 }
659 EngineError::StartInputRefused { .. } => simple_engine_fields("StartInputRefused", source),
660 EngineError::SignalRefused { .. } => simple_engine_fields("SignalRefused", source),
661 EngineError::Schedule { .. } => simple_engine_fields("Schedule", source),
662 EngineError::Runtime { .. } => simple_engine_fields("Runtime", source),
663 EngineError::Gate3BifReplacementMissing { .. } => {
664 simple_engine_fields("Gate3BifReplacementMissing", source)
665 }
666 EngineError::StartupRecoveryNotDeferred => {
667 simple_engine_fields("StartupRecoveryNotDeferred", source)
668 }
669 EngineError::StartupRecoveryAlreadyRan => {
670 simple_engine_fields("StartupRecoveryAlreadyRan", source)
671 }
672 EngineError::StartupCatchupBeforeWorkflowRecovery => {
673 simple_engine_fields("StartupCatchupBeforeWorkflowRecovery", source)
674 }
675 EngineError::StartupRecoverySlotPoisoned => {
676 simple_engine_fields("StartupRecoverySlotPoisoned", source)
677 }
678 EngineError::CleanupExecutorPoisoned => {
679 simple_engine_fields("CleanupExecutorPoisoned", source)
680 }
681 EngineError::CleanupExecutorShutdownTimedOut { .. } => {
682 simple_engine_fields("CleanupExecutorShutdownTimedOut", source)
683 }
684 EngineError::RunNotInHistory { .. } => simple_engine_fields("RunNotInHistory", source),
685 EngineError::ProcessExitRegistryPoisoned => {
686 simple_engine_fields("ProcessExitRegistryPoisoned", source)
687 }
688 EngineError::ProcessExitOwnershipPoisoned { .. } => {
689 simple_engine_fields("ProcessExitOwnershipPoisoned", source)
690 }
691 EngineError::ProcessExitStatePoisoned { .. }
692 | EngineError::ProcessExitSubscriptionUnavailable
693 | EngineError::ProcessExitDrainerSpawn { .. }
694 | EngineError::ProcessExitDrainerPoisoned
695 | EngineError::ProcessExitOutcomeMissingAfterEvent { .. }
696 | EngineError::ProcessExitEventStreamDisconnected
697 | EngineError::ProcessExitDrainerShutdownTimedOut { .. }
698 | EngineError::ProcessExitDrainerPanicked => process_exit::drainer_trace(source),
699 EngineError::ProcessExitCallbackDispatcherPoisoned
700 | EngineError::ProcessExitCallbackDispatcherUnavailable
701 | EngineError::ProcessExitCallbackDispatcherShutdownTimedOut { .. } => {
702 process_exit::callback_trace(source)
703 }
704 EngineError::ProcessExitAlreadyTerminal { .. } => {
705 simple_engine_fields("ProcessExitAlreadyTerminal", source)
706 }
707 EngineError::ActivityDeliveryPoisoned { .. } => {
708 simple_engine_fields("ActivityDeliveryPoisoned", source)
709 }
710 EngineError::RegistryPoisoned => simple_engine_fields("RegistryPoisoned", source),
711 EngineError::CatalogPoisoned => simple_engine_fields("CatalogPoisoned", source),
712 EngineError::NifRegistration { .. } => simple_engine_fields("NifRegistration", source),
713 EngineError::SignalRouter(_) => simple_engine_fields("SignalRouter", source),
714 EngineError::Query(query) => simple_engine_fields(engine::query_error_type(query), source),
715 }
716}
717
718fn simple_engine_fields<'a>(
719 error_type: &'static str,
720 source: &'a EngineError,
721) -> ErrorTraceFields<'a> {
722 ErrorTraceFields {
723 error_type: Cow::Borrowed(error_type),
724 store_error_type: None,
725 reason: source,
726 }
727}
728
729fn store_trace_fields(source: &StoreError) -> ErrorTraceFields<'_> {
730 ErrorTraceFields {
731 error_type: Cow::Borrowed("StoreError"),
732 store_error_type: Some(engine::store_error_type(source)),
733 reason: source,
734 }
735}
736
737fn wire_from_engine(source: &EngineError) -> WireError {
738 use EngineError as E;
739 use engine::backend_wire as backend;
740
741 match source {
742 EngineError::WorkflowNotFound { .. } => {
743 WireError::not_found_with_type("WorkflowNotFound", source.to_string())
744 }
745 EngineError::InvalidState { reason } => engine::invalid_state_wire(reason),
747 E::TerminalWriterUnavailable { .. }
753 | E::TerminalWriterHeld { .. }
754 | E::WorkflowWriterHeld { .. }
758 | E::RunIsRecoverable { .. }
759 | E::NoResidencyVerdict { .. } => engine::invalid_state_wire(&source.to_string())
760 .with_error_type(never_alive_error_type(source)),
761 EngineError::ScheduleNotFound { .. } => {
762 WireError::not_found_with_type("ScheduleNotFound", source.to_string())
763 }
764 EngineError::ShuttingDown => {
765 WireError::not_running_with_type("ShuttingDown", source.to_string())
766 }
767 E::EngineTaskEpochClosed { .. } => backend("EngineTaskEpochClosed", source),
788 EngineError::Store(store) => wire_from_store(store),
789 EngineError::Durability(durability) => engine::durability_wire(durability, source),
790 E::MissingStore => backend("MissingStore", source),
791 E::MissingVisibilityStore => backend("MissingVisibilityStore", source),
792 E::ConflictingEventPublisher => backend("ConflictingEventPublisher", source),
793 E::EventStreaming(_) => backend("EventStreaming", source),
794 E::Load { .. } => backend("Load", source),
795 EngineError::UnenforceableContract { .. } => {
798 WireError::invalid_input(source.to_string()).with_error_type("UnenforceableContract")
799 }
800 EngineError::UnknownVersion { .. } => {
802 WireError::not_found_with_type("UnknownVersion", source.to_string())
803 }
804 EngineError::VersionPinned { .. } => {
805 WireError::version_pinned(source.to_string()).with_error_type("VersionPinned")
806 }
807 EngineError::RouteActive { .. } => {
808 WireError::version_pinned(source.to_string()).with_error_type("RouteActive")
809 }
810 EngineError::ManifestMismatch { .. } => {
811 WireError::invalid_input(source.to_string()).with_error_type("ManifestMismatch")
812 }
813 E::Package(_) => backend("Package", source),
814 E::ContractIdentity { .. } => engine::contract_refusal_wire("ContractIdentity", source),
815 E::NoQueueDeclaration { .. } => engine::contract_refusal_wire("NoQueueDeclaration", source),
816 E::StartInputRefused { .. } => engine::declared_contract_wire("StartInputRefused", source),
817 E::SignalRefused { .. } => engine::declared_contract_wire("SignalRefused", source),
818 EngineError::Schedule { .. } => backend("Schedule", source),
819 E::Runtime { .. } => backend("Runtime", source),
820 E::Gate3BifReplacementMissing { .. } => backend("Gate3BifReplacementMissing", source),
821 E::StartupRecoveryNotDeferred => backend("StartupRecoveryNotDeferred", source),
824 E::StartupRecoveryAlreadyRan => backend("StartupRecoveryAlreadyRan", source),
825 E::StartupCatchupBeforeWorkflowRecovery => {
826 backend("StartupCatchupBeforeWorkflowRecovery", source)
827 }
828 E::StartupRecoverySlotPoisoned => backend("StartupRecoverySlotPoisoned", source),
829 E::CleanupExecutorPoisoned => backend("CleanupExecutorPoisoned", source),
830 E::CleanupExecutorShutdownTimedOut { .. } => {
831 backend("CleanupExecutorShutdownTimedOut", source)
832 }
833 E::RunNotInHistory { .. } => backend("RunNotInHistory", source),
839 E::ProcessExitRegistryPoisoned => backend("ProcessExitRegistryPoisoned", source),
840 E::ProcessExitOwnershipPoisoned { .. } => backend("ProcessExitOwnershipPoisoned", source),
841 EngineError::ProcessExitStatePoisoned { .. }
842 | EngineError::ProcessExitSubscriptionUnavailable
843 | EngineError::ProcessExitDrainerSpawn { .. }
844 | EngineError::ProcessExitDrainerPoisoned
845 | EngineError::ProcessExitOutcomeMissingAfterEvent { .. }
846 | EngineError::ProcessExitEventStreamDisconnected
847 | EngineError::ProcessExitDrainerShutdownTimedOut { .. }
848 | EngineError::ProcessExitDrainerPanicked => process_exit::drainer_wire(source),
849 EngineError::ProcessExitCallbackDispatcherPoisoned
850 | EngineError::ProcessExitCallbackDispatcherUnavailable
851 | EngineError::ProcessExitCallbackDispatcherShutdownTimedOut { .. } => {
852 process_exit::callback_wire(source)
853 }
854 E::ProcessExitAlreadyTerminal { .. } => backend("ProcessExitAlreadyTerminal", source),
855 E::ActivityDeliveryPoisoned { .. } => backend("ActivityDeliveryPoisoned", source),
856 E::CatalogPoisoned => backend("CatalogPoisoned", source),
857 E::RegistryPoisoned => backend("RegistryPoisoned", source),
858 E::NifRegistration { .. } => backend("NifRegistration", source),
859 E::SignalRouter(_) => backend("SignalRouter", source),
860 EngineError::Query(query) => engine::query_wire(query, source),
861 }
862}
863
864fn wire_from_store(source: &StoreError) -> WireError {
865 match source {
866 StoreError::SequenceConflict { .. } => WireError::new_with_type(
867 aion_proto::WireErrorCode::SequenceConflict,
868 "SequenceConflict",
869 source.to_string(),
870 ),
871 StoreError::NotFound { .. } => {
872 WireError::not_found_with_type("NotFound", source.to_string())
873 }
874 StoreError::NotOwner { .. } => {
875 WireError::not_owner(source.to_string()).with_error_type("NotOwner")
876 }
877 StoreError::Backend(_) => WireError::backend_with_type("Backend", source.to_string()),
878 StoreError::Serialization(_) => {
879 WireError::backend_with_type("Serialization", source.to_string())
880 }
881 }
882}
883
884#[cfg(test)]
885#[path = "error_tests.rs"]
886mod tests;