-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Expand file tree
/
Copy path_process.py
More file actions
74 lines (61 loc) · 1.98 KB
/
Copy path_process.py
File metadata and controls
74 lines (61 loc) · 1.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
"""Helpers for terminating SDK-spawned CLI process trees."""
from __future__ import annotations
import os
import signal
import subprocess
import sys
import time
def popen_process_group_kwargs() -> dict[str, bool]:
"""Return Popen kwargs that isolate spawned CLI servers in their own process group."""
if sys.platform == "win32":
return {}
return {"start_new_session": True}
def _terminate_windows_process_tree(pid: int, *, force: bool) -> None:
args = ["taskkill", "/T", "/PID", str(pid)]
if force:
args.insert(1, "/F")
kwargs: dict = {
"capture_output": True,
"check": False,
}
if hasattr(subprocess, "CREATE_NO_WINDOW"):
kwargs["creationflags"] = subprocess.CREATE_NO_WINDOW
subprocess.run(args, **kwargs)
def terminate_owned_cli_process(
process: subprocess.Popen | None,
*,
graceful: bool = True,
timeout: float = 5.0,
) -> bool:
"""Terminate an SDK-owned CLI process and its descendants.
Returns True when the process is no longer running.
"""
if process is None:
return True
if process.poll() is not None:
return True
pid = process.pid
if sys.platform == "win32":
_terminate_windows_process_tree(pid, force=not graceful)
else:
sig = signal.SIGTERM if graceful else signal.SIGKILL
try:
os.killpg(os.getpgid(pid), sig)
except ProcessLookupError:
return True
except OSError:
try:
if graceful:
process.terminate()
else:
process.kill()
except OSError:
return process.poll() is not None
deadline = time.monotonic() + timeout
while time.monotonic() < deadline:
if process.poll() is not None:
return True
time.sleep(0.05)
if graceful:
return terminate_owned_cli_process(process, graceful=False, timeout=timeout)
return process.poll() is not None