Fix zombie daemon blocking ORB restart in ORBDaemonController

os.kill(pid, 0) returns success for zombie (defunct) processes.
Added ps stat check — if process is in Z state, treat as dead and
clean up PID file so subsequent start() calls work correctly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
main
I Luk Kim 4 months ago
parent b98442b28a
commit ee2f1f6f84

@ -759,13 +759,30 @@ class ORBDaemonController:
@property @property
def running(self) -> bool: def running(self) -> bool:
"""True if the daemon process is alive (PID file + kill-0 check).""" """True if the daemon process is alive (PID file + kill-0 check, zombie-safe)."""
pid_file = self._pid_file() pid_file = self._pid_file()
if not pid_file.exists(): if not pid_file.exists():
return False return False
try: try:
pid = int(pid_file.read_text().strip()) pid = int(pid_file.read_text().strip())
os.kill(pid, 0) # signal 0: probe without sending anything os.kill(pid, 0) # signal 0: probe without sending anything
# kill-0 succeeds for zombie processes too — check /proc or ps to exclude zombies
try:
import subprocess as _sp
result = _sp.run(
["ps", "-p", str(pid), "-o", "stat="],
capture_output=True, text=True, timeout=2,
)
stat = result.stdout.strip()
if stat.startswith("Z"):
# Zombie — treat as dead, clean up PID file
try:
pid_file.unlink()
except Exception:
pass
return False
except Exception:
pass # if ps fails, trust kill-0 result
return True return True
except (ValueError, ProcessLookupError, PermissionError, OSError): except (ValueError, ProcessLookupError, PermissionError, OSError):
# Process dead or PID stale — remove the file # Process dead or PID stale — remove the file

Loading…
Cancel
Save