Skip to content

serve: a session's end stops its bash jobs, in a daemon too - #263

Merged
jaredLunde merged 1 commit into
mainfrom
jared/serve-jobs-session-end
Oct 16, 2026
Merged

jaredLunde merged 1 commit into
mainfrom
jared/serve-jobs-session-end

Conversation

@jaredLunde

Copy link
Copy Markdown
Contributor

Fixes serve audit defect #7 (resource leak, from #253).

Problem

A reaped daemon session never stopped its bash jobs. ExecCell::runner() returned CellRunner(self.clone()), and the cell owned the job table; every running job's task holds the runner. So task → runner → cell → table → job → task: the table never dropped while a job ran. The job outlived its session, unreachable and silent, holding its port and the tenant's exec target until the daemon exited. ARCHITECTURE.md's "the session's end kills its jobs" was only true in stdio mode, where process exit runs kill_live_jobs.

Fix

  • ExecCell keeps its dispatch half in a CellRoute (target + strict). CellRunner and CellFs clone only the route, so the cycle is gone.
  • serve_session stops its jobs explicitly as it returns, whatever ended it (EOF, reap, supersede, shutdown). It runs stop_all on the blocking pool, because the kills block and the daemon's runtime is current-thread, and reports them in a bash_jobs_stopped frame.
  • ARCHITECTURE.md updated.

Tests

  • New crates/agent/tests/bash_jobs_serve_daemon.rs::a_reaped_session_stops_its_jobs: a daemon with a 1 s idle reap. The test detaches after the model leaves nohup sleep 89 & running, then checks the process dies while the daemon stays up. It fails on main: the job is still alive after 15 s.
  • cargo fmt, clippy --all-targets -D warnings (agent + agent-core) and dprint check are clean. The agent + agent-core nextest suites passed 3901/3902. The one failure, tool_reactor_stall::the_responsiveness_probe_catches_a_tool_that_blocks_without_cpu, is load-sensitive; it passes on rerun and this change doesn't touch it.

🤖 Generated with Claude Code

https://claude.ai/code/session_01JimHGjsfk2Ktm5GxyZJKKk

A reaped (or otherwise ended) daemon session never stopped its bash jobs.
The cell's runner cloned the whole ExecCell, job table included, and every
running job's task holds that runner: task -> runner -> cell -> table ->
job -> task. The table never dropped, so the job ran on, unreachable and
silent, until the daemon exited (the stdio test passed only because
process exit runs kill_live_jobs).

- ExecCell splits its dispatch half (CellRoute: target + strict) from the
  job table; the runner and filesystem backend clone only the route, so
  there is no cycle.
- serve_session stops its jobs explicitly as it returns (stop_all on the
  blocking pool, reported in a bash_jobs_stopped frame), whatever ended it.

Test: bash_jobs_serve_daemon.rs reaps a detached daemon session and checks
its adopted `nohup sleep &` dies while the daemon stays up (fails on main
after 15 s).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JimHGjsfk2Ktm5GxyZJKKk
@jaredLunde
jaredLunde enabled auto-merge October 16, 2026 06:27
@jaredLunde
jaredLunde added this pull request to the merge queue Oct 16, 2026
Merged via the queue into main with commit 55ef3f7 Oct 16, 2026
13 checks passed
@jaredLunde
jaredLunde deleted the jared/serve-jobs-session-end branch October 16, 2026 06:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant