use std::collections::{HashMap, HashSet};
use crate::compose::types::ComposeFile;
use crate::error::Result;
use super::readiness::SharedReady;
use super::Engine;
impl Engine {
#[allow(clippy::too_many_arguments)]
pub(super) async fn start_services_by_dependency(
&self,
levels: &[Vec<String>],
file: &ComposeFile,
enabled: &HashSet<String>,
target_set: &Option<HashSet<String>>,
present: &HashSet<String>,
existing_hash: &HashMap<String, String>,
no_recreate: bool,
force_recreate: bool,
start: bool,
readiness: &HashMap<String, SharedReady<'_>>,
) -> Result<()> {
let scheduled: Vec<&str> = levels.iter().flatten().map(String::as_str).collect();
let permits = std::sync::Arc::new(tokio::sync::Semaphore::new(
super::parallel::MAX_LIFECYCLE_CONCURRENCY,
));
let done: std::collections::HashMap<&str, tokio::sync::watch::Sender<bool>> = scheduled
.iter()
.map(|name| (*name, tokio::sync::watch::channel(false).0))
.collect();
let enabled = &enabled;
let target_set = &target_set;
let present = &present;
let existing_hash = &existing_hash;
let readiness = &readiness;
let started = scheduled.iter().map(|name| {
let permits = permits.clone();
let done = &done;
let deps: Vec<tokio::sync::watch::Receiver<bool>> = file
.services
.get(*name)
.map(|s| s.depends_on.service_names())
.unwrap_or_default()
.into_iter()
.filter_map(|d| done.get(d.as_str()).map(|tx| tx.subscribe()))
.collect();
async move {
for mut rx in deps {
while !*rx.borrow_and_update() {
if rx.changed().await.is_err() {
break;
}
}
}
let _permit = permits.acquire().await;
let result = self
.up_one_service(
name,
file,
enabled,
target_set,
present,
existing_hash,
no_recreate,
force_recreate,
start,
readiness,
)
.await;
if result.is_ok() {
if let Some(tx) = done.get(*name) {
let _ = tx.send(true);
}
}
result
}
});
futures_util::future::try_join_all(started).await?;
Ok(())
}
}