From 3c36cf1c40da116376fa2807d18624ed8a4afed4 Mon Sep 17 00:00:00 2001 From: archipelago Date: Tue, 23 Jun 2026 13:39:19 -0400 Subject: [PATCH] fix(companion): stop image_exists journal flood that drops the UI websocket MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit image_exists ran `podman image inspect ` via .status() (inherits the service stdout) with no --format, so every hit dumped the image's full ~249-line manifest JSON into the journal — once per companion image, every reconcile pass (.228: 21.6k journal lines / 10 min, 4131 inspect dumps). The service never crashed (NRestarts=0); the sustained journald/IO flood starved the async runtime and dropped the UI /ws/db websocket -> constant "connection lost"/reconnect. Discard the child's stdout/stderr; only the exit status is used. Co-Authored-By: Claude Opus 4.8 (1M context) --- core/archipelago/src/container/companion.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/core/archipelago/src/container/companion.rs b/core/archipelago/src/container/companion.rs index 96809dd2..d861046c 100644 --- a/core/archipelago/src/container/companion.rs +++ b/core/archipelago/src/container/companion.rs @@ -285,7 +285,15 @@ async fn ensure_image_present(spec: &CompanionSpec) -> Result { async fn image_exists(image: &str) -> bool { let mut cmd = Command::new("podman"); - cmd.args(["image", "inspect", image]); + // Only the exit status matters. WITHOUT a `--format`, `podman image inspect` + // prints the image's full multi-KB manifest JSON; `.status()` inherits the + // service's stdout, so on a hit that whole blob lands in the journal — once + // per companion image, every reconcile pass. That flood spikes journald + + // IO and starves the async runtime (UI websocket then drops → "connection + // lost"/reconnect). Discard the child's stdout/stderr; we read neither. + cmd.args(["image", "inspect", image]) + .stdout(std::process::Stdio::null()) + .stderr(std::process::Stdio::null()); match tokio::time::timeout(COMPANION_IMAGE_CHECK_TIMEOUT, cmd.status()).await { Ok(Ok(status)) => status.success(), Ok(Err(err)) => {