fix(cron): propagate cleanupCliLiveSessionOnRunEnd to isolated cron CLI branch - #97227
Conversation
|
Codex review: needs maintainer review before merge. Reviewed June 28, 2026, 4:36 AM ET / 08:36 UTC. Summary PR surface: Source +1, Tests +2. Total +3 across 2 files. Reproducibility: yes. at source level: current main lacks the cleanup flag on isolated cron CLI runs, and the PR body includes after-fix gateway logs through the changed path. I did not run a live multi-cron stress reproduction in this read-only review. Review metrics: 1 noteworthy metric.
Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Merge this focused CLI live-session cleanup after maintainer acceptance of the isolated cron one-shot boundary, while keeping MCP loopback and embedded-worker lifecycle work in separate canonical items. Do we have a high-confidence way to reproduce the issue? Yes, at source level: current main lacks the cleanup flag on isolated cron CLI runs, and the PR body includes after-fix gateway logs through the changed path. I did not run a live multi-cron stress reproduction in this read-only review. Is this the best way to solve the issue? Yes. The narrowest maintainable fix is to propagate the existing CLI live-session cleanup flag at the isolated cron CLI boundary while avoiding the process-global MCP cleanup flag in this PR. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 9c95abd49d45. Label changesLabel justifications:
Evidence reviewedPR surface: Source +1, Tests +2. Total +3 across 2 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
…flag Verify cleanupCliLiveSessionOnRunEnd is passed on both the initial and retry CLI runs during isolated cron interim-ack retry loops. Proves the inner boundary is safe: each runCliAgent call creates a fresh context, so cleanup cannot affect the retry's live session.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ae064b0 to
54fce9d
Compare
|
Land-ready verification for
The runtime fix is at the correct owner boundary, persistent cron sessions retain reuse behavior, and there are no remaining review findings. |
|
Merged via squash.
|
…LI branch (openclaw#97227) * fix(cron): propagate cleanupCliLiveSessionOnRunEnd to isolated cron CLI branch * test(cron): add CLI interim retry coverage for isolated cron cleanup flag Verify cleanupCliLiveSessionOnRunEnd is passed on both the initial and retry CLI runs during isolated cron interim-ack retry loops. Proves the inner boundary is safe: each runCliAgent call creates a fresh context, so cleanup cannot affect the retry's live session. * fix(cron): remove unused variable in interim retry test Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test(cron): trim redundant cleanup retry coverage --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Peter Steinberger <steipete@golden-gate.local>
…LI branch (openclaw#97227) * fix(cron): propagate cleanupCliLiveSessionOnRunEnd to isolated cron CLI branch * test(cron): add CLI interim retry coverage for isolated cron cleanup flag Verify cleanupCliLiveSessionOnRunEnd is passed on both the initial and retry CLI runs during isolated cron interim-ack retry loops. Proves the inner boundary is safe: each runCliAgent call creates a fresh context, so cleanup cannot affect the retry's live session. * fix(cron): remove unused variable in interim retry test Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test(cron): trim redundant cleanup retry coverage --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Peter Steinberger <steipete@golden-gate.local>
What Problem This Solves
Isolated cron CLI workers (
src/cron/isolated-agent/run-executor.tsat line ~306) callrunCliAgentwithout passingcleanupCliLiveSessionOnRunEnd, so worker processes spawned by CLI live sessions during cron runs are never cleaned up after the run completes. Over time, stale worker processes accumulate on the host, causing high load and slow responses.The cleanup contract already exists in the CLI runner types and implementation (
cli-runner/types.ts,cli-runner.ts), but was not wired for the isolated cron CLI code path.Fixes #76171
Why This Change Was Made
Added
cleanupCliLiveSessionOnRunEnd: params.job.sessionTarget === "isolated"to therunCliAgentcall insrc/cron/isolated-agent/run-executor.ts. This uses the existing session-target check ("isolated"when the job runs in isolated mode) to signal that the CLI live session should be cleaned up at run end — exactly the same pattern used elsewhere in the codebase.No other changes are needed: the CLI runner already handles the cleanup when this flag is set.
User Impact
Users running cron jobs with isolated session targets (
sessionTarget: "isolated") would previously see growing process counts and degrading host performance after repeated cron cycles. After this fix, each isolated cron CLI worker cleans up its live sessions at run end, preventing stale process accumulation.No impact on non-isolated cron jobs or other run modes.
Fix scope and issue relationship
This PR fully fixes #76171 for the reported symptom (stale worker process accumulation). The canonical root cause — confirmed by ClawSweeper source-level review (June 26, 2026), contributor YusukeIt0, and this PR's own analysis — is that
cleanupCliLiveSessionOnRunEndwas not propagated to the isolated cron CLI branch inrunCliAgent. The flag triggers:The embedded cron branch already had its corresponding cleanup (
cleanupBundleMcpOnRunEnd→retireSessionMcpRuntimeForSessionKey, which is session-scoped and safe for concurrent runs). The only gap was the CLI branch missing its live-session cleanup flag.Explicit non-goal:
cleanupBundleMcpOnRunEndwas intentionally NOT added to the CLI branch. In the CLI runner (cli-runner.ts:476-482), this flag callscloseMcpLoopbackServer()— a process-global operation that would close the shared loopback HTTP server, breaking concurrent cron runs' MCP tool calls. The embedded runner'scleanupBundleMcpOnRunEnduses a different, session-scoped mechanism (retireSessionMcpRuntimeForSessionKey). Adding process-level MCP cleanup to the CLI branch would introduce a worse bug than the one being fixed. Safe MCP runtime cleanup for CLI cron paths requires a session-scoped approach (tracked by PR #85241) and is not necessary to resolve the worker accumulation reported in #76171 — the stale workers are Claude CLI subprocesses, not MCP server processes.Evidence
1. Runtime proof: isolated cron CLI run through the changed run-executor.ts path
Methodology: Temporary
process.stderr.writemarkers were inserted at three points — (a)src/cron/isolated-agent/run-executor.ts:306(CLI branch entry), (b)src/agents/cli-runner.ts:469(cleanup branch entry), and (c)src/agents/cli-runner.ts:476(cleanup complete). Aclaude-cliCLI backend was configured pointing at the local Claude Code installation (/usr/local/node24131/bin/claude, v2.1.187). An isolated cron job (sessionTarget=isolated,model=claude-cli/claude-sonnet-4-6) was created and executed via the gateway. Markers were removed from final commits.Build and verify markers in dist:
Create and run isolated cron job:
Gateway stderr — the changed run-executor.ts CLI branch entered, cleanup triggered, cleanup completed:
OpenClaw production log — Claude live session lifecycle confirms worker spawned, ran, and exited:
Complete code path verified at runtime (all three markers confirmed + production log):
This is the exact code path changed by this PR: an isolated cron agent turn with a CLI provider flows through
run-executor.ts(where the fix lives) →runCliAgent(which now receivescleanupCliLiveSessionOnRunEnd: true) → the cleanup branch → the worker subprocess is signaled and exits cleanly. Before the fix, the "CRON EXECUTOR CLI branch" marker would still fire, but "CRON CLI cleanup TRIGGERED" would NOT —closeClaudeLiveSessionForContextwas never called, leaving the worker alive.Temporary config used for proof (added to
~/.openclaw/openclaw.json;claude-cliCLI backend is a bundled Anthropic plugin):(Config retained; useful for future CLI-backend testing.)
2. Inner boundary safety proof (P1 addressed)
Question: Does running cleanup inside
runCliAgentbreak CLI interim retries, where a secondrunCliAgentcall reuses the same session?Answer: No. Each
runCliAgentcall creates a fresh context viaprepareCliRunContextat line 454—455, which in turn creates a fresh ClaudeLiveSession spawn. The cleanup key isbuildClaudeLiveKey(context)keyed on the session identity; after the first call's cleanup, the key is removed fromliveSessions, so the second call's spawn is completely independent.3. CLI interim retry test coverage (P1 addressed)
Two new tests added to
src/cron/isolated-agent/run.interim-retry.test.ts:Test A — "passes cleanupCliLiveSessionOnRunEnd on both the initial and retry CLI runs":
isCliProviderMock = true(CLI path)runCliAgentreturns "On it, grabbing…" (interim ack)runCliAgentreturns concrete resultcleanupCliLiveSessionOnRunEnd === trueon both callsTest B — "still passes cleanupCliLiveSessionOnRunEnd when the first turn is already a concrete result (no retry)":
isCliProviderMock = true(CLI path)runCliAgentreturns concrete result (no retry needed)cleanupCliLiveSessionOnRunEnd === trueon the single call4. Code-level proof: before (main) vs after (this fix)
src/cron/isolated-agent/run-executor.ts— CLI branch:5. Cleanup contract (already exists, now wired up)
src/agents/cli-runner/types.ts:144:cleanupCliLiveSessionOnRunEnd?: booleansrc/agents/cli-runner.ts:467-474:src/agents/cli-runner/claude-live-session.ts:441-464:src/process/supervisor/supervisor.ts:232-239:6. Process cleanup mechanism proof
A real OS process was spawned to validate the kill chain:
7. Test evidence: CLI branch cleanup flag assertion
8. Test evidence: closeClaudeLiveSessionForContext invoked when flag is set
9. Full test suite (all paths)
10. Type check and lint
pnpm check:test-types— passedBehavior addressed: Isolated cron CLI workers now set
cleanupCliLiveSessionOnRunEndwhensessionTarget === "isolated", ensuring Claude CLI subprocesses (the zombies reported in #76171) are terminated after each run via the ProcessSupervisor's SIGTERM→SIGKILL mechanism. Proof verified at three independent levels: live gateway cron execution, built binary inspection, and full test suite (25 tests across 3 files).