diff --git a/hermes_cli/cron.py b/hermes_cli/cron.py index 486eaba9518cf..a15c7bc6b558d 100644 --- a/hermes_cli/cron.py +++ b/hermes_cli/cron.py @@ -78,6 +78,15 @@ def _builtin_gateway_liveness() -> Optional[bool]: try: if _active_cron_provider_name() != "builtin": return True # external provider fires jobs without the gateway + # The gateway runtime lock is held for exactly the gateway's lifetime, so it + # is a more reliable "is the ticker's process alive" signal than PID scanning + # — and inside the gateway process it short-circuits to True, so the in-gateway + # cron tool never emits a false "gateway not running" (find_gateway_pids can + # transiently miss the gateway just after a restart). + from gateway.status import is_gateway_runtime_lock_active + + if is_gateway_runtime_lock_active(): + return True from hermes_cli.gateway import find_gateway_pids return bool(find_gateway_pids()) diff --git a/tools/mcp_tool.py b/tools/mcp_tool.py index c1c80e5adb18a..98b1cd25e784d 100644 --- a/tools/mcp_tool.py +++ b/tools/mcp_tool.py @@ -2999,11 +2999,9 @@ def _stdio_children_dead(self) -> bool: # os.kill probe below only runs when psutil is unavailable. import psutil - if not psutil.pid_exists(pid): - continue # this one is dead - return True # alive (signal permission irrelevant for liveness) - return False # at least one child alive - return True + if psutil.pid_exists(pid): + return False # at least one child alive → not all have exited + return True # no tracked child is alive → every child has exited async def _watch_stdio_children(self) -> None: """Poll child liveness while a stdio RPC is in flight (#81995).