MCPcopy Index your code
hub / github.com/AutoForgeAI/autoforge / kill_process_tree

Function kill_process_tree

server/utils/process_utils.py:40–134  ·  view source on GitHub ↗

Kill a process and all its child processes. On Windows, subprocess.terminate() only kills the immediate process, leaving orphaned child processes (e.g., spawned browser instances, coding/testing agents). This function uses psutil to kill the entire process tree. Args: proc:

(proc: subprocess.Popen, timeout: float = 5.0)

Source from the content-addressed store, hash-verified

38
39
40def kill_process_tree(proc: subprocess.Popen, timeout: float = 5.0) -> KillResult:
41 """Kill a process and all its child processes.
42
43 On Windows, subprocess.terminate() only kills the immediate process, leaving
44 orphaned child processes (e.g., spawned browser instances, coding/testing agents).
45 This function uses psutil to kill the entire process tree.
46
47 Args:
48 proc: The subprocess.Popen object to kill
49 timeout: Seconds to wait for graceful termination before force-killing
50
51 Returns:
52 KillResult with status and statistics about the termination
53 """
54 result = KillResult(status="success", parent_pid=proc.pid)
55
56 try:
57 parent = psutil.Process(proc.pid)
58 # Get all children recursively before terminating
59 children = parent.children(recursive=True)
60 result.children_found = len(children)
61
62 logger.debug(
63 "Killing process tree: PID %d with %d children",
64 proc.pid, len(children)
65 )
66
67 # Terminate children first (graceful)
68 for child in children:
69 try:
70 logger.debug("Terminating child PID %d (%s)", child.pid, child.name())
71 child.terminate()
72 except (psutil.NoSuchProcess, psutil.AccessDenied) as e:
73 # NoSuchProcess: already dead
74 # AccessDenied: Windows can raise this for system processes or already-exited processes
75 logger.debug("Child PID %d already gone or inaccessible: %s", child.pid, e)
76
77 # Wait for children to terminate
78 gone, still_alive = psutil.wait_procs(children, timeout=timeout)
79 result.children_terminated = len(gone)
80
81 logger.debug(
82 "Children after graceful wait: %d terminated, %d still alive",
83 len(gone), len(still_alive)
84 )
85
86 # Force kill any remaining children
87 for child in still_alive:
88 try:
89 logger.debug("Force-killing child PID %d", child.pid)
90 child.kill()
91 result.children_killed += 1
92 except (psutil.NoSuchProcess, psutil.AccessDenied) as e:
93 logger.debug("Child PID %d gone during force-kill: %s", child.pid, e)
94
95 if result.children_killed > 0:
96 result.status = "partial"
97

Callers 4

_run_initializerMethod · 0.90
_read_outputMethod · 0.90
stop_featureMethod · 0.90
stop_allMethod · 0.90

Calls 1

KillResultClass · 0.85

Tested by

no test coverage detected