Skip to main content

engenho_runtime/
error.rs

1//! Typed runtime errors — `thiserror`, no `anyhow` in the lib.
2
3use engenho_apiserver::ServerError;
4use engenho_config::ConfigError;
5use engenho_store::StoreError;
6
7/// Everything that can go wrong booting or shutting down a [`crate::Runtime`].
8#[derive(Debug, thiserror::Error)]
9pub enum RuntimeError {
10    /// Config failed `validate()` or a section was incoherent.
11    #[error("config error: {0}")]
12    Config(#[from] ConfigError),
13
14    /// The store mesh failed to start, initialize, or take leadership.
15    #[error("store error: {0}")]
16    Store(#[from] StoreError),
17
18    /// The apiserver failed to bind or serve.
19    #[error("apiserver error: {0}")]
20    Server(#[from] ServerError),
21
22    /// Raft leadership wasn't reached within the configured timeout.
23    /// The store started but never elected a leader, so no `propose`
24    /// (Node registration, apiserver writes) could ever succeed.
25    #[error("store did not reach leadership within {seconds}s")]
26    LeadershipTimeout {
27        /// The configured leadership timeout that elapsed.
28        seconds: u32,
29    },
30
31    /// `listen_addr` couldn't be parsed into a `SocketAddr`.
32    #[error("invalid listen_addr {addr:?}: {source}")]
33    ListenAddr {
34        /// The unparseable address string.
35        addr: String,
36        /// The parse error.
37        #[source]
38        source: std::net::AddrParseError,
39    },
40
41    /// At shutdown, the Runtime could not become the sole owner of the
42    /// store `Arc` (a driver task or apiserver handler still holds a
43    /// clone). `terminate` consumes `StoreMesh` and requires the only
44    /// strong ref; this surfaces the leak rather than hanging.
45    #[error(
46        "could not acquire sole store ownership for terminate ({strong_count} strong refs remain)"
47    )]
48    StoreStillShared {
49        /// How many strong refs remained when `try_unwrap` failed.
50        strong_count: usize,
51    },
52
53    /// Failed to build or persist the boot-time kubeconfig
54    /// (`data_dir/kubeconfig`). Carries the emitter / io message.
55    #[error("kubeconfig emission failed: {0}")]
56    Kubeconfig(String),
57
58    /// A filesystem operation while writing the kubeconfig failed.
59    #[error("kubeconfig io error at {path}: {source}")]
60    KubeconfigIo {
61        /// The path the operation targeted.
62        path: std::path::PathBuf,
63        /// The underlying io error.
64        #[source]
65        source: std::io::Error,
66    },
67}
68
69engenho_substrate::impl_error_kind! {
70    RuntimeError {
71        (Config(_)) => "config",
72        (Store(_)) => "store",
73        (Server(_)) => "server",
74        { LeadershipTimeout { .. } } => "leadership_timeout",
75        { ListenAddr { .. } } => "listen_addr",
76        { StoreStillShared { .. } } => "store_still_shared",
77        (Kubeconfig(_)) => "kubeconfig",
78        { KubeconfigIo { .. } } => "kubeconfig_io",
79    }
80}