diff --git a/hermes_state.py b/hermes_state.py index a4d9b9429ac..a2a019a7a98 100644 --- a/hermes_state.py +++ b/hermes_state.py @@ -46,6 +46,11 @@ def _compression_lock_holder_process_is_dead(holder: str) -> bool: only when the kernel proves that PID no longer exists; legacy/unstructured holders and permission errors remain protected until normal TTL expiry. """ + # Python's os.kill(pid, 0) is a non-destructive liveness probe on POSIX. + # On Windows, any non-CTRL signal value is implemented with + # TerminateProcess, so fall back to TTL-only recovery there. + if os.name == "nt": + return False match = _COMPRESSION_LOCK_HOLDER_PID_RE.search(holder or "") if match is None: return False @@ -59,7 +64,7 @@ def _compression_lock_holder_process_is_dead(holder: str) -> bool: os.kill(pid, 0) except ProcessLookupError: return True - except (PermissionError, OSError): + except (PermissionError, OSError, OverflowError): return False return False diff --git a/tests/test_hermes_state_compression_locks.py b/tests/test_hermes_state_compression_locks.py index 2655a75c05d..05aaaeb3ab1 100644 --- a/tests/test_hermes_state_compression_locks.py +++ b/tests/test_hermes_state_compression_locks.py @@ -137,12 +137,30 @@ def test_unstructured_holder_waits_for_ttl( assert db.try_acquire_compression_lock( "sess1", "legacy_holder", ttl_seconds=300 ) is True - kill = monkeypatch.setattr( + monkeypatch.setattr( hermes_state.os, "kill", lambda *_args: pytest.fail("unstructured holder must not probe a PID"), ) - assert kill is None + assert db.try_acquire_compression_lock( + "sess1", "pid=525252:tid=2:agent=def:nonce=other", ttl_seconds=300 + ) is False + + +def test_windows_uses_ttl_only_without_os_kill( + db: SessionDB, monkeypatch: pytest.MonkeyPatch +) -> None: + holder = "pid=424242:tid=1:agent=abc:nonce=windows" + assert db.try_acquire_compression_lock( + "sess1", holder, ttl_seconds=300 + ) is True + monkeypatch.setattr(hermes_state.os, "name", "nt") + monkeypatch.setattr( + hermes_state.os, + "kill", + lambda *_args: pytest.fail("Windows must not use os.kill as a PID probe"), + ) + assert db.try_acquire_compression_lock( "sess1", "pid=525252:tid=2:agent=def:nonce=other", ttl_seconds=300 ) is False