make agent_config_pending async — the sync git fork on every sweep starved the runtime under IO load

This commit is contained in:
damocles 2026-07-02 20:17:00 +02:00 committed by mara
commit cf1f7288bf
2 changed files with 11 additions and 4 deletions

View file

@ -38,9 +38,15 @@ pub fn current_flake_rev(hyperhive_flake: &str) -> Option<String> {
/// 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())

View file

@ -70,7 +70,7 @@ pub async fn build_all(coord: &Coordinator) -> Vec<ContainerView> {
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