fix(serve): only "no such process" from ps means the Desktop parent is gone

The stderr sniff also matched "not found", which BSD ps prints for an
unsupported column ("ps: lstart: keyword not found", rc=1, verified on
macOS). That would have classified a healthy parent as dead and os._exit'd
the backend — the fail-unsafe direction the watchdog must never take. Keep
the explicit missing-process message only; the macos_only test now pins the
"keyword not found" case as a plain OSError. The standalone
ProcessLookupError test (already green on main) folds into the degrade test.
This commit is contained in:
kshitijk4poor
2026-09-11 11:02:16 +05:30
committed by kshitij
parent 60562ed81a
commit e7eed649a6
2 changed files with 9 additions and 12 deletions

View File

@@ -75,10 +75,10 @@ def _process_start_marker(pid: int) -> str:
marker = result.stdout.strip()
if result.returncode == 0 and marker:
return f"ps:{marker}"
stderr_lower = result.stderr.lower()
if (result.returncode == 1 and not marker) or any(
msg in stderr_lower for msg in ("no such process", "not found")
):
# rc==1 with empty output is the portable "no such pid"; "No such process" widens that for ps
# builds that say so explicitly. Any other failure stays an OSError so the watchdog degrades to
# pid liveness instead of exiting on a healthy backend.
if (result.returncode == 1 and not marker) or "no such process" in result.stderr.lower():
raise ProcessLookupError(pid)
raise OSError(f"ps could not inspect PID {pid}: {result.stderr.strip()}")

View File

@@ -191,22 +191,19 @@ def test_parent_watchdog_degrades_to_pid_liveness_when_marker_probe_raises_oserr
assert _is_serve_orphaned(4242, marker, pid_exists=lambda _pid: True,
process_start_marker=broken_marker_probe) is False
def test_parent_watchdog_detects_dead_parent_on_process_lookup_error():
"""#80204: ``ProcessLookupError`` from the marker probe means the parent is gone, whatever
a (possibly recycled) pid liveness check says."""
def lookup_error_probe(pid: int) -> str:
raise ProcessLookupError(pid)
assert _is_serve_orphaned(4242, "ps:Thu Aug 20 22:33:11 2026", pid_exists=lambda _pid: True,
# ProcessLookupError is conclusive on its own, whatever a recycled-pid liveness check says.
assert _is_serve_orphaned(4242, marker, pid_exists=lambda _pid: True,
process_start_marker=lookup_error_probe) is True
@pytest.mark.macos_only
def test_ps_marker_probe_classifies_missing_process_vs_other_ps_failures(monkeypatch):
"""The darwin ``ps`` probe raises ``ProcessLookupError`` only for a missing-process message;
any other non-zero exit stays a plain ``OSError`` so the watchdog degrades instead of killing
a healthy backend."""
"""The darwin ``ps`` probe raises ``ProcessLookupError`` only for an explicit missing-process
message; any other unknown failure stays a plain ``OSError`` so the watchdog degrades instead
of killing a healthy backend."""
import subprocess
from hermes_cli import web_server_lifecycle