mod event_relay;
mod lifecycle;
mod management;
mod shutdown_workflow;
#[cfg(test)]
mod tests;
use std::sync::{
Arc,
atomic::{AtomicBool, Ordering},
};
use tokio::sync::mpsc;
use tokio_util::sync::CancellationToken;
use self::shutdown_workflow::ShutdownCoordinator;
use crate::core::{
SupervisorConfig, TaskDefaults,
alive::AliveTracker,
registry::{Registry, RegistryCommand},
};
use crate::{events::Bus, subscribers::SubscriberSet};
pub(crate) struct SupervisorCore {
settings: CoreSettings,
pub(super) bus: Bus,
subs: Arc<SubscriberSet>,
alive: Arc<AliveTracker>,
registry: Arc<Registry>,
runtime_token: CancellationToken,
started: AtomicBool,
startup_gate: std::sync::Mutex<()>,
running: AtomicBool,
shutting_down: AtomicBool,
shutdown: ShutdownCoordinator,
#[cfg(feature = "controller")]
controller: std::sync::OnceLock<std::sync::Weak<crate::controller::Controller>>,
admission_gate: std::sync::Mutex<()>,
cmd_tx: mpsc::Sender<RegistryCommand>,
subscriber_handle: std::sync::Mutex<Option<tokio::task::JoinHandle<()>>>,
}
pub(crate) struct CoreSettings {
runtime: SupervisorConfig,
task_defaults: TaskDefaults,
}
impl CoreSettings {
pub(crate) fn new(runtime: SupervisorConfig, task_defaults: TaskDefaults) -> Self {
Self {
runtime,
task_defaults,
}
}
}
impl std::fmt::Debug for SupervisorCore {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("SupervisorCore")
.field("runtime", &self.settings.runtime)
.field("task_defaults", &self.settings.task_defaults)
.field("started", &self.started.load(Ordering::Relaxed))
.finish_non_exhaustive()
}
}
impl SupervisorCore {
pub(crate) fn new_internal(
settings: CoreSettings,
bus: Bus,
subs: Arc<SubscriberSet>,
alive: Arc<AliveTracker>,
registry: Arc<Registry>,
runtime_token: CancellationToken,
cmd_tx: mpsc::Sender<RegistryCommand>,
) -> Arc<Self> {
Arc::new(Self {
settings,
bus,
subs,
alive,
registry,
runtime_token,
started: AtomicBool::new(false),
startup_gate: std::sync::Mutex::new(()),
running: AtomicBool::new(false),
shutting_down: AtomicBool::new(false),
shutdown: ShutdownCoordinator::new(),
#[cfg(feature = "controller")]
controller: std::sync::OnceLock::new(),
admission_gate: std::sync::Mutex::new(()),
cmd_tx,
subscriber_handle: std::sync::Mutex::new(None),
})
}
pub(crate) fn is_shutting_down(&self) -> bool {
self.shutting_down.load(Ordering::Acquire)
}
pub(crate) fn runtime_config(&self) -> &SupervisorConfig {
&self.settings.runtime
}
pub(crate) fn task_defaults(&self) -> &TaskDefaults {
&self.settings.task_defaults
}
#[cfg(feature = "controller")]
pub(crate) fn shutdown_started_token(&self) -> CancellationToken {
self.shutdown.started.clone()
}
#[cfg(feature = "controller")]
pub(crate) fn attach_controller(&self, controller: &Arc<crate::controller::Controller>) {
assert!(
self.controller.set(Arc::downgrade(controller)).is_ok(),
"the controller lifecycle may be attached only once"
);
}
}