fix(appd): kill file portal process on all early-return paths in supervise()

Runtime spawn failure, READY timeout, and abort-during-startup all
previously returned without killing the portal child process or removing
its socket file. Extracted kill_portal() to consolidate cleanup and
call it in each of those three paths.
This commit is contained in:
Marco Allegretti 2026-03-11 18:20:16 +01:00
parent aa95be6244
commit 0877bd970d

View file

@ -87,6 +87,14 @@ fn resolve_preopens(app_id: &str) -> Vec<(String, String)> {
preopens
}
async fn kill_portal(portal: Option<(PathBuf, tokio::process::Child)>) {
if let Some((sock, mut child)) = portal {
let _ = child.kill().await;
let _ = child.wait().await;
let _ = std::fs::remove_file(&sock);
}
}
fn portal_socket_path(session_id: u64) -> Option<PathBuf> {
let runtime_dir = std::env::var("XDG_RUNTIME_DIR").ok()?;
let dir = PathBuf::from(runtime_dir).join("weft");
@ -181,6 +189,7 @@ pub(crate) async fn supervise(
Ok(c) => c,
Err(e) => {
tracing::warn!(session_id, %app_id, error = %e, "failed to spawn runtime; marking session stopped");
kill_portal(portal).await;
let mut reg = registry.lock().await;
reg.set_state(session_id, AppStateKind::Stopped);
let _ = reg.broadcast().send(Response::AppState {
@ -229,6 +238,7 @@ pub(crate) async fn supervise(
Some(Err(_elapsed)) => {
tracing::warn!(session_id, %app_id, "READY timeout after 30s; killing process");
let _ = child.kill().await;
kill_portal(portal).await;
let mut reg = registry.lock().await;
reg.set_state(session_id, AppStateKind::Stopped);
let _ = reg.broadcast().send(Response::AppState {
@ -240,6 +250,7 @@ pub(crate) async fn supervise(
None => {
tracing::info!(session_id, %app_id, "abort during startup; killing process");
let _ = child.kill().await;
kill_portal(portal).await;
let mut reg = registry.lock().await;
reg.set_state(session_id, AppStateKind::Stopped);
let _ = reg.broadcast().send(Response::AppState {