From 45f8d94df6ce9eee8f3dd91e01166453483cabae Mon Sep 17 00:00:00 2001 From: Bryan Helmkamp Date: Tue, 7 Apr 2026 20:57:52 -0400 Subject: [PATCH] refactor(server): stop writing worker stderr scratch logs Route subprocess worker stderr directly into server tracing and remove the scratch-file sink. Update the run-directory docs to reflect that runtime now only documents blob materialization here. --- docs/reference/run-directory.mdx | 2 +- lib/crates/fabro-server/src/server.rs | 23 +++-------------------- 2 files changed, 4 insertions(+), 21 deletions(-) diff --git a/docs/reference/run-directory.mdx b/docs/reference/run-directory.mdx index af9f4ca8f..a39c5885b 100644 --- a/docs/reference/run-directory.mdx +++ b/docs/reference/run-directory.mdx @@ -28,7 +28,7 @@ The naming format is `YYYYMMDD-{run_id}`, where `run_id` is the ULID assigned to These paths are local runtime state and caches, not the canonical run record. - **`worktree/`** — When running in worktree mode, Fabro creates a Git worktree here as the working directory for agents and commands. -- **`runtime/`** — Local runtime files. Today this is mainly materialized blob payloads under `runtime/blobs/` and worker stderr logs for server-managed subprocesses. +- **`runtime/`** — Local runtime files. Today this is mainly materialized blob payloads under `runtime/blobs/`. - **`cache/artifacts/files/`** — Captured artifact files organized by node and retry, plus a `manifest.json` for each retry directory. - **`nodes/{manager_node}_{visit}/child/`** — Nested scratch directories for manager-loop child workflows. diff --git a/lib/crates/fabro-server/src/server.rs b/lib/crates/fabro-server/src/server.rs index 96562240d..4af46f9d3 100644 --- a/lib/crates/fabro-server/src/server.rs +++ b/lib/crates/fabro-server/src/server.rs @@ -248,7 +248,6 @@ enum ExecutionResult { CancelledBySignal, } -const WORKER_STDERR_LOG: &str = "worker.stderr.log"; const WORKER_CANCEL_GRACE: Duration = Duration::from_secs(5); const WORKER_CONTROL_QUEUE_CAPACITY: usize = 8; const WORKER_CONTROL_ENQUEUE_TIMEOUT: Duration = Duration::from_secs(1); @@ -2731,29 +2730,13 @@ fn update_live_run_from_event(state: &Arc, run_id: RunId, event: &RunE } } -async fn drain_worker_stderr( - run_id: RunId, - run_dir: PathBuf, - stderr: ChildStderr, -) -> anyhow::Result<()> { - let log_path = run_dir.join("runtime").join(WORKER_STDERR_LOG); - if let Some(parent) = log_path.parent() { - fs::create_dir_all(parent).await?; - } - let mut log_file = fs::OpenOptions::new() - .create(true) - .append(true) - .open(&log_path) - .await?; +async fn drain_worker_stderr(run_id: RunId, stderr: ChildStderr) -> anyhow::Result<()> { let mut lines = BufReader::new(stderr).lines(); while let Some(line) = lines.next_line().await? { - log_file.write_all(line.as_bytes()).await?; - log_file.write_all(b"\n").await?; - tracing::warn!(run_id = %run_id, worker_stderr = %line); + tracing::warn!(run_id = %run_id, "Worker stderr: {line}"); } - log_file.flush().await?; Ok(()) } @@ -3786,7 +3769,7 @@ async fn execute_run_subprocess(state: Arc, run_id: RunId) { } let control_task = tokio::spawn(pump_worker_control_jsonl(stdin, control_rx)); - let stderr_task = tokio::spawn(drain_worker_stderr(run_id, run_dir.clone(), stderr)); + let stderr_task = tokio::spawn(drain_worker_stderr(run_id, stderr)); let wait_status = match child.wait().await { Ok(status) => status,