use super::{launch_error, runtime_status, startable_service, DaemonRuntime, RuntimeMutationError};
use nomoreide_core::bundle::{self, BundleOrderError};
use nomoreide_core::config::{Config, ServiceDef};
use nomoreide_daemon_client::protocol::ServiceRuntimeStatus;
impl DaemonRuntime {
pub(crate) async fn start_bundle(
&self,
name: &str,
) -> Result<Vec<ServiceRuntimeStatus>, RuntimeMutationError> {
self.require_start_allowed()?;
let _permit = self.mutation_gate.read().await;
self.require_start_allowed()?;
let config = self.config().await?;
let order = bundle::start_order(&config, name).map_err(|error| order_error(name, error))?;
let admitted = order
.iter()
.map(|service| startable_service(&config, service))
.collect::<Result<Vec<_>, _>>()?;
let mut statuses = Vec::with_capacity(admitted.len());
for service in admitted {
self.await_dependencies(&config, service).await;
self.process_manager
.start_service(service)
.await
.map_err(launch_error)?;
statuses.push(
self.process_manager
.service_status(&service.name)
.map(runtime_status)
.ok_or(RuntimeMutationError::ServiceStartFailed)?,
);
}
Ok(statuses)
}
pub(crate) async fn stop_bundle(
&self,
name: &str,
) -> Result<Vec<ServiceRuntimeStatus>, RuntimeMutationError> {
self.require_stop_allowed()?;
let _permit = self.mutation_gate.read().await;
self.require_stop_allowed()?;
let config = self.config().await?;
let order = bundle::stop_order(&config, name).map_err(|error| order_error(name, error))?;
let mut statuses = Vec::with_capacity(order.len());
let mut failed = false;
for service in &order {
if self.process_manager.service_status(service).is_none() {
startable_service(&config, service)?;
}
match self.process_manager.stop_service(service).await {
Ok(()) => statuses.push(
self.process_manager
.service_status(service)
.map(runtime_status)
.unwrap_or_else(|| super::stopped_status(service)),
),
Err(_) => failed = true,
}
}
if failed {
return Err(RuntimeMutationError::CleanupFailed);
}
Ok(statuses)
}
pub(crate) async fn restart_bundle(
&self,
name: &str,
) -> Result<Vec<ServiceRuntimeStatus>, RuntimeMutationError> {
self.stop_bundle(name).await?;
self.start_bundle(name).await
}
async fn await_dependencies(&self, config: &Config, service: &ServiceDef) {
for dependency in service.depends_on.iter().flatten() {
if let Ok(def) = startable_service(config, dependency) {
bundle::wait_for_service_ready(&self.process_manager, def, bundle::READY_TIMEOUT)
.await;
}
}
}
}
fn order_error(name: &str, error: BundleOrderError) -> RuntimeMutationError {
match error {
BundleOrderError::NotRegistered => RuntimeMutationError::BundleNotFound(name.to_string()),
BundleOrderError::DependencyCycle(message) => {
RuntimeMutationError::DependencyCycle(message)
}
}
}