Skip to content

bug: Orphaned Claude processes accumulate in agent containers after execution timeout #61

Description

@vybe

Summary

When agent executions time out at the backend level, the backend marks the execution as failed in the database but does not kill the spawned claude process inside the agent container. Over time, orphaned processes accumulate, consuming memory and inflating the "running" execution count in stats.

Component

Backend / Execution Manager

Priority

P2

Observed Behavior

  1. Backend sends a task to an agent container by spawning a claude process (via docker exec)
  2. If the execution exceeds the backend's timeout, the backend marks the execution as failed in schedule_executions
  3. The claude OS process inside the container continues running indefinitely
  4. The /api/agents/{name}/executions/{id}/terminate endpoint returns "Execution not found in agent" because the backend has already lost track of the process
  5. Failed executions show cost: null, context_used: null — confirming the backend abandoned them without receiving a response

Real-world impact observed: 6 concurrent claude processes found in a single agent container (5 orphaned), each consuming ~160MB RAM (~800MB wasted). One "running" execution had been stuck for 3+ hours. The orphaned processes had to be manually killed via docker exec ... kill.

Root Cause

The backend does not maintain a mapping from execution ID to the container PID of the spawned claude process. When a timeout occurs, there is no handle to send a SIGTERM/SIGKILL to the child process. The backend simply stops waiting and writes failed to the database.

Additionally, the execution stats API (/api/agents/execution-stats) counts these zombie executions as running, since their status was never updated in all tracking layers.

Reproduction Steps

  1. Send a long-running task to an agent (e.g., a command that takes >10 minutes like installing large Python packages)
  2. Wait for the backend execution timeout to fire
  3. Observe the execution is marked failed in the database
  4. Run docker exec agent-{name} ps aux | grep claude — the process is still alive
  5. Repeat several times — orphaned processes accumulate
  6. Check /api/agents/execution-statsrunning_count is inflated

Suggested Fix

Several approaches (not mutually exclusive):

Option A: Track PID and kill on timeout

When spawning docker exec agent-{name} claude ..., capture the PID. On timeout, issue docker exec agent-{name} kill {pid}.

Option B: Container-side reaper

Add a lightweight watchdog process inside agent containers that periodically checks for claude processes with no active parent/session and kills them.

Option C: Backend cleanup on status check

When the backend detects executions stuck in running status past their timeout + grace period, proactively exec into the container to kill stale processes and update the DB status.

Option D: Process group management

Spawn claude processes in their own process group so the entire tree can be killed with a single signal.

Environment

  • Trinity version: 9f910e9
  • Docker version: 29.2.1
  • OS: Ubuntu 22.04.5 LTS

Related

  • Execution spawning logic in the backend execution manager
  • /api/agents/{name}/executions/{id}/terminate endpoint
  • schedule_executions table (status field lifecycle)
  • /api/agents/execution-stats endpoint (running count accuracy)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions