Skip to content

fix: reap stale background processes to prevent gateway starvation (#76115) - #76183

Closed
RelaxJonh wants to merge 1 commit into
NousResearch:mainfrom
RelaxJonh:fix/stale-process-reap-76115
Closed

fix: reap stale background processes to prevent gateway starvation (#76115)#76183
RelaxJonh wants to merge 1 commit into
NousResearch:mainfrom
RelaxJonh:fix/stale-process-reap-76115

Conversation

@RelaxJonh

Copy link
Copy Markdown
Contributor

Summary

Fixes #76115.

When an agent turn spawns a background subprocess (e.g. pnpm build) and that turn gets abandoned, the subprocess runs indefinitely inside the hermes-gateway cgroup. A single runaway build can push the cgroup past its MemoryHigh limit, causing kernel throttling and swap-thrashing that starves the gateway event loop — every messaging platform disconnects and every cron fails with "provider timeout".

Changes

  • tools/process_registry.py: Added a background daemon thread (_stale_sweep_loop) that periodically checks for running processes exceeding MAX_ACTIVE_PROCESS_AGE (24h default). Long-running processes are killed via the existing kill_process infrastructure (handles SIGKILL/SIGTERM on POSIX, taskkill /T /F on Windows). Added STALE_SWEEP_INTERVAL constant (300s). Added _reap_stale_running() method with logging.

Design

  • Uses threading.Event.wait() for clean shutdown — no busy-wait loop
  • Daemon thread dies with the process — no manual cleanup needed
  • Uses existing kill_process() for proper process-tree teardown
  • Respects MAX_ACTIVE_PROCESS_AGE (configurable via session_reset.bg_process_max_age_hours)
  • Logs each kill at INFO level for audit trail

…ousResearch#76115)

Add a background sweep thread to ProcessRegistry that kills running
background processes exceeding MAX_ACTIVE_PROCESS_AGE (default 24h).

Without this, abandoned or stuck tool subprocesses (e.g. pnpm build)
run indefinitely, consuming unbounded memory until the gateway cgroup
hits MemoryHigh — starving the asyncio event loop and causing all
platforms and crons to time out.

Changes:
- Add STALE_SWEEP_INTERVAL constant (300s / 5 min)
- Add _stale_sweep_loop() daemon thread started at registry init
- Add _reap_stale_running() method using existing kill_process()
  which handles process-tree teardown (SIGKILL/SIGTERM POSIX,
  taskkill /T /F Windows)

Fixes NousResearch#76115
@alt-glitch alt-glitch added type/bug Something isn't working comp/tools Tool registry, model_tools, toolsets tool/terminal Terminal execution and process management P1 High — major feature broken, no workaround sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state duplicate This issue or pull request already exists labels Aug 1, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Duplicate of #76172: the current diffs are byte-identical and add the same global stale-process sweep for #76115.

@teknium1

teknium1 commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Thanks for addressing a verified process-lifetime gap.

Problems

  • gateway/run.py:5584-5600 uses session_reset.bg_process_max_age_hours only to stop a process from blocking session reset; it explicitly does not kill the process. The proposed sweep instead defaults directly to MAX_ACTIVE_PROCESS_AGE, so it does not respect that configuration as claimed.
  • The report in Abandoned agent turn leaks its background subprocess (e.g. next build) unbounded → gateway cgroup hits MemoryHigh, event loop starves, all platforms/crons time out #76115 describes an ~11-hour runaway build, while this sweep acts only after 24 hours; it cannot prevent that documented failure window.
  • website/docs/user-guide/messaging/index.md:274-281 explicitly preserves legitimate multi-day background jobs. A global age-based kill changes that behavior without distinguishing an abandoned turn from successful-turn work.
  • gh pr diff 76183 shows no tests for the new concurrent reaper path.

Suggested changes

Automated hermes-sweeper review.

@teknium1 teknium1 added sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-broad Sweeper blast radius: broad — a core path most sessions hit labels Aug 1, 2026
@kshitijk4poor

Copy link
Copy Markdown
Collaborator

Closing as duplicate of #76188 (@JoaoMarcos44) — that PR implements turn-scoped reaping (only kills processes the abandoned turn created) with 4 test files and gateway integration, vs the age-based blind sweep here which would kill legitimate long-running background processes older than 24h. Your PR was also byte-for-byte identical to #76172. Thanks for the contribution!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/tools Tool registry, model_tools, toolsets duplicate This issue or pull request already exists P1 High — major feature broken, no workaround sweeper:blast-broad Sweeper blast radius: broad — a core path most sessions hit sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state tool/terminal Terminal execution and process management type/bug Something isn't working

Projects

None yet

4 participants