From 799756c9f0930f5f20b91abd35dd145bb32cc24b Mon Sep 17 00:00:00 2001 From: "takemi.ohama" Date: Sat, 31 Oct 2026 18:59:38 +0000 Subject: [PATCH] =?UTF-8?q?Fix:=20=E7=B5=82=E4=BA=86=E3=81=AE=E9=80=94?= =?UTF-8?q?=E4=B8=AD=E3=81=AE=20CLI=20=E3=82=92=E7=9B=A3=E8=A6=96=E3=81=8C?= =?UTF-8?q?=20PIDFILE=5FBAD=20=E3=81=A7=E6=AD=A2=E3=82=81=E3=82=8B?= =?UTF-8?q?=E4=B8=8D=E5=AE=9A=E3=81=AE=E5=A4=B1=E6=95=97=E3=82=92=E7=9B=B4?= =?UTF-8?q?=E3=81=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit psutil は終了の途中(ゾンビになる前)の pid の起動の引数を、例外でなく空で返す。 cmdline_contains がこれを False(別のプロセス)と取り、すぐ終わる見本の CLI を 監視が PIDFILE_BAD で止めていた(CI の test_external_ai_run が claude / agy / kiro で 不定に落ちる。run 41230540718・41185581443・41107004636・40185190257)。 空の引数は読めない(None)とする。 Co-Authored-By: Claude Opus 5.5 --- plugins/ndf/scripts/lib/procs.py | 9 +++++++-- plugins/ndf/scripts/tests/test_lib_procs.py | 11 +++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/plugins/ndf/scripts/lib/procs.py b/plugins/ndf/scripts/lib/procs.py index 039364470..9c7c303f0 100644 --- a/plugins/ndf/scripts/lib/procs.py +++ b/plugins/ndf/scripts/lib/procs.py @@ -82,14 +82,19 @@ def pid_is_zombie(pid: int) -> bool: def cmdline_contains(pid: int, expected: str) -> bool | None: - """pid の起動の引数(空白でつないだもの)が `expected` を含むか(大文字と小文字を区別しない)。読めなければ None。""" + """pid の起動の引数(空白でつないだもの)が `expected` を含むか(大文字と小文字を区別しない)。読めなければ None。 + + 空の引数も読めないとみなす。終了の途中(ゾンビになる前)の pid は、psutil が例外でなく `[]` を返す。 + False(別のプロセス)と取ると、すぐ終わる CLI を監視が PIDFILE_BAD で止める(CI の不定の失敗)。 + """ p = _process(pid) if p is None: return None try: - return expected.lower() in " ".join(p.cmdline()).lower() + args = p.cmdline() except psutil.Error: return None + return expected.lower() in " ".join(args).lower() if args else None def parent_and_name(pid: int) -> tuple[int, str] | None: diff --git a/plugins/ndf/scripts/tests/test_lib_procs.py b/plugins/ndf/scripts/tests/test_lib_procs.py index 34b19fbd0..42fbce818 100644 --- a/plugins/ndf/scripts/tests/test_lib_procs.py +++ b/plugins/ndf/scripts/tests/test_lib_procs.py @@ -51,6 +51,17 @@ def test_zombie_counts_as_dead_and_missing_pids_are_quiet(): assert procs.wait_gone(p.pid, timeout=0.1) +def test_empty_cmdline_of_an_exiting_process_is_unreadable(monkeypatch): + """終了の途中(ゾンビになる前)の pid は psutil が空の引数を返す。別のプロセス(False)と取らない。""" + + class Exiting: + def cmdline(self): + return [] + + monkeypatch.setattr(procs, "_process", lambda pid: Exiting()) + assert procs.cmdline_contains(12345, "claude") is None + + def test_memory_and_cgroup(tmp_path: Path): avail, total = procs.memory_available() assert 0 < avail <= total