[Fix] IPC, cli, daemon

This commit is contained in:
Alex-Emmet 2026-07-21 23:05:34 +02:00
commit 56aad3a023
32 changed files with 1356 additions and 399 deletions

View file

@ -3,21 +3,123 @@ use iota_state::DaemonState;
use std::sync::Arc;
use std::time::Duration;
use sysinfo::{RefreshKind, System};
use tokio::sync::watch;
use tokio_util::sync::CancellationToken;
/// Reason the daemon is shutting down.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ShutdownReason {
Stop,
Restart,
Fatal(String),
}
impl ShutdownReason {
pub fn exit_code(&self) -> i32 {
match self {
ShutdownReason::Stop => 0,
ShutdownReason::Restart => 75,
ShutdownReason::Fatal(_) => 1,
}
}
}
/// Tracks the lifecycle phase of the daemon for IPC visibility.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum StartupPhase {
Starting,
MigratingStorage,
LoadingUsers,
StartingServices,
Ready,
Degraded,
Stopping,
}
impl From<StartupPhase> for iota_ipc::StartupPhase {
fn from(phase: StartupPhase) -> Self {
match phase {
StartupPhase::Starting => iota_ipc::StartupPhase::Starting,
StartupPhase::MigratingStorage => iota_ipc::StartupPhase::MigratingStorage,
StartupPhase::LoadingUsers => iota_ipc::StartupPhase::LoadingUsers,
StartupPhase::StartingServices => iota_ipc::StartupPhase::StartingServices,
StartupPhase::Ready => iota_ipc::StartupPhase::Ready,
StartupPhase::Degraded => iota_ipc::StartupPhase::Degraded,
StartupPhase::Stopping => iota_ipc::StartupPhase::Stopping,
}
}
}
/* This wrapper exposes daemon state as IPC-safe snapshots while preserving a
* single owned state instance for all daemon subsystems. */
#[derive(Clone, Default)]
* single owned state instance for all daemon subsystems. The cancellation token
* is the single lifecycle signal all subsystems check it instead of a
* separate boolean. */
pub struct DaemonRuntime {
pub state: Arc<DaemonState>,
pub cancellation: CancellationToken,
pub shutdown_tx: watch::Sender<Option<ShutdownReason>>,
pub startup_phase: watch::Sender<StartupPhase>,
pub degraded_reason: watch::Sender<Option<String>>,
}
impl Clone for DaemonRuntime {
fn clone(&self) -> Self {
Self {
state: self.state.clone(),
cancellation: self.cancellation.clone(),
shutdown_tx: self.shutdown_tx.clone(),
startup_phase: self.startup_phase.clone(),
degraded_reason: self.degraded_reason.clone(),
}
}
}
impl Default for DaemonRuntime {
fn default() -> Self {
Self::new()
}
}
impl DaemonRuntime {
pub fn new() -> Self {
let (shutdown_tx, _) = watch::channel(None);
let (startup_phase, _) = watch::channel(StartupPhase::Starting);
let (degraded_reason, _) = watch::channel(None);
Self {
state: Arc::new(DaemonState::new()),
cancellation: CancellationToken::new(),
shutdown_tx,
startup_phase,
degraded_reason,
}
}
pub fn shutdown(&self, reason: ShutdownReason) {
self.cancellation.cancel();
let _ = self.shutdown_tx.send(Some(reason));
}
pub fn shutdown_reason(&self) -> Option<ShutdownReason> {
self.shutdown_tx.borrow().clone()
}
pub fn is_shutting_down(&self) -> bool {
self.cancellation.is_cancelled()
}
pub fn set_startup_phase(&self, phase: StartupPhase) {
let _ = self.startup_phase.send(phase);
}
pub fn current_startup_phase(&self) -> StartupPhase {
*self.startup_phase.borrow()
}
pub fn mark_degraded(&self, reason: String) {
let _ = self.degraded_reason.send(Some(reason.clone()));
let _ = self.startup_phase.send(StartupPhase::Degraded);
}
pub fn snapshot(&self) -> StateSnapshot {
let state = self
.state
@ -41,7 +143,7 @@ impl DaemonRuntime {
let mut system = System::new_with_specifics(RefreshKind::everything());
let mut counter = 0.0;
loop {
if *runtime.state.shutdown.read().await {
if runtime.is_shutting_down() {
break;
}
system.refresh_cpu_all();