Watch
0
0
Fork
You've already forked hyperhive
0

hive-c0re: bound the read-only container listing and systemctl status calls

priv_client::list_containers now waits at most 30s (LIST_WAIT) for
hive-priv's `nixos-container list`, via the existing `within` helper. Its
periodic callers (crash_watch, agent_sockets, swarm_agent_status, wanted,
mcp_sockets, swarm_status via container_view) already treat an Err as a
skipped cycle, so a hung listing no longer stops their loops for good.

lifecycle::is_running / unit_state run `systemctl is-active` with
kill_on_drop and a 10s timeout (IS_ACTIVE_TIMEOUT); a timeout warns and
reads as not-running / UnitState::Other, the same as a systemctl that
could not be spawned. The new lifecycle::running_state returns None for
that case, and crash_watch keeps the agent's previous observation on None
so a hung systemctl is neither reported as a crash nor as a recovery.

`call` itself and every mutating op (start/stop/destroy/send-snapshot/
daemon-reload) stay unbounded.

Closes #5061
This commit is contained in:
atlas 2026-10-09 15:30:32 +02:00
commit 3cb7be29cf
5 changed files with 106 additions and 19 deletions

View file

@ -449,3 +449,27 @@ fn is_actionable_nix_line_keeps_warnings_and_errors_demotes_chatter() {
assert!(!is_actionable_nix_line(line), "{line}");
}
}
#[tokio::test]
async fn a_hung_systemctl_reads_as_unknown_within_the_bound() {
let started = tokio::time::Instant::now();
let got = output_within(
std::time::Duration::from_millis(20),
std::future::pending::<std::io::Result<()>>(),
&["is-active"],
)
.await;
assert!(got.is_none());
assert!(started.elapsed() < std::time::Duration::from_secs(5));
}
#[tokio::test]
async fn a_systemctl_answer_inside_the_bound_passes_through() {
let got = output_within(
std::time::Duration::from_secs(5),
async { Ok(7_u8) },
&["is-active"],
)
.await;
assert_eq!(got, Some(7));
}