diff --git a/hive-c0re/src/auto_update.rs b/hive-c0re/src/auto_update.rs index b2d9ef0a..40d81b6e 100644 --- a/hive-c0re/src/auto_update.rs +++ b/hive-c0re/src/auto_update.rs @@ -38,9 +38,15 @@ pub fn current_flake_rev(hyperhive_flake: &str) -> Option { /// deployed (i.e. the applied HEAD differs from the sha currently locked in /// meta's flake.lock). This is the semantic the dashboard `needs_update` chip /// conveys: "there is a config change ready to apply via rebuild." -#[must_use] -pub fn agent_config_pending(name: &str, deployed_sha: Option<&str>) -> bool { - let applied_head = std::process::Command::new("git") +/// +/// Async on purpose: this runs per agent inside `container_view::build_all`, +/// which fires on the ~10s dashboard sweep, every `AgentStatus` request, and +/// every `rescan_containers_and_emit` after a lifecycle step. A synchronous +/// `git` fork here blocks a tokio worker for the whole exec — under +/// nix-build disk saturation that's long enough that concurrent sweeps +/// starved the runtime and stalled the per-agent sockets. +pub async fn agent_config_pending(name: &str, deployed_sha: Option<&str>) -> bool { + let applied_head = tokio::process::Command::new("git") .args([ "-C", &format!("/var/lib/hyperhive/applied/{name}"), @@ -48,6 +54,7 @@ pub fn agent_config_pending(name: &str, deployed_sha: Option<&str>) -> bool { "HEAD", ]) .output() + .await .ok() .filter(|o| o.status.success()) .and_then(|o| String::from_utf8(o.stdout).ok()) diff --git a/hive-c0re/src/container_view.rs b/hive-c0re/src/container_view.rs index 74c41dd1..9cdda653 100644 --- a/hive-c0re/src/container_view.rs +++ b/hive-c0re/src/container_view.rs @@ -70,7 +70,7 @@ pub async fn build_all(coord: &Coordinator) -> Vec { let deployed_full = locked .get(&format!("agent-{logical}")) .map(std::string::String::as_str); - let needs_update = crate::auto_update::agent_config_pending(&logical, deployed_full); + let needs_update = crate::auto_update::agent_config_pending(&logical, deployed_full).await; let deployed_sha = deployed_full.map(|s| s[..s.len().min(12)].to_owned()); let pending_reminders = coord .broker