From 9f526d7dcdd87c570f0b37223c19cb34ccfbc5be Mon Sep 17 00:00:00 2001 From: Danilo Horta Date: Tue, 17 Sep 2024 14:51:39 +0100 Subject: [PATCH] Handle parent process not alive error in Sched class - Import ParentNotAliveError in cli.py and sched.py - Add ParentNotAliveError to __all__ in errors.py - Implement ParentNotAliveError handling in Sched class methods - Update ready function in cli.py to handle ParentNotAliveError --- h3daemon/h3daemon/cli.py | 15 ++++++++++----- h3daemon/h3daemon/errors.py | 5 ++++- h3daemon/h3daemon/sched.py | 29 ++++++++++++++++++++++++----- 3 files changed, 38 insertions(+), 11 deletions(-) diff --git a/h3daemon/h3daemon/cli.py b/h3daemon/h3daemon/cli.py index 19f59db..9c9b3f3 100644 --- a/h3daemon/h3daemon/cli.py +++ b/h3daemon/h3daemon/cli.py @@ -9,7 +9,7 @@ from typer import echo from h3daemon.connect import find_free_port -from h3daemon.errors import CouldNotPossessError +from h3daemon.errors import CouldNotPossessError, ParentNotAliveError from h3daemon.hmmfile import HMMFile from h3daemon.pidfile import create_pidfile from h3daemon.sched import Sched @@ -116,12 +116,17 @@ def ready(hmmfile: Path, wait: bool = O_WAIT): if wait: wait_until(sched.is_ready) - if sched.is_ready(): - typer.echo("Daemon is ready!") - raise typer.Exit(0) - else: + try: + if sched.is_ready(): + typer.echo("Daemon is ready!") + raise typer.Exit(0) + else: + typer.echo("Daemon is NOT ready...") + raise typer.Exit(1) + except ParentNotAliveError: typer.echo("Daemon is NOT ready...") raise typer.Exit(1) + except CouldNotPossessError as x: typer.echo(str(x)) raise typer.Exit(1) diff --git a/h3daemon/h3daemon/errors.py b/h3daemon/h3daemon/errors.py index 0f48164..933b654 100644 --- a/h3daemon/h3daemon/errors.py +++ b/h3daemon/h3daemon/errors.py @@ -1,4 +1,7 @@ -__all__ = ["ChildNotFoundError", "CouldNotPossessError"] +__all__ = ["ParentNotAliveError", "ChildNotFoundError", "CouldNotPossessError"] + + +class ParentNotAliveError(RuntimeError): ... class ChildNotFoundError(RuntimeError): ... diff --git a/h3daemon/h3daemon/sched.py b/h3daemon/h3daemon/sched.py index 21e2715..8aed748 100644 --- a/h3daemon/h3daemon/sched.py +++ b/h3daemon/h3daemon/sched.py @@ -10,7 +10,11 @@ from pidlockfile import PIDLockFile from h3daemon.connect import find_free_port -from h3daemon.errors import ChildNotFoundError, CouldNotPossessError +from h3daemon.errors import ( + ChildNotFoundError, + CouldNotPossessError, + ParentNotAliveError, +) from h3daemon.hmmfile import HMMFile from h3daemon.master import Master from h3daemon.pidfile import create_pidfile @@ -122,11 +126,13 @@ def run(self, hmmfile: str, cport: int, wport: int): try: master = spawn_master(hmmfile, cport, wport) worker = spawn_worker(wport) + def shutdown(_): try: self.terminate_children(15) except psutil.TimeoutExpired: self.kill_children() + psutil.wait_procs([master.process, worker.process], callback=shutdown) finally: try: @@ -145,14 +151,27 @@ def kill_parent(self): def terminate_children(self, timeout: Union[float, None] = None): for x in self._proc.children(): - x.terminate() - x.wait(timeout) + try: + x.terminate() + x.wait(timeout) + except psutil.NoSuchProcess: + pass def terminate_parent(self, timeout: Union[float, None] = None): - self._proc.terminate() - self._proc.wait(timeout) + try: + self._proc.terminate() + self._proc.wait(timeout) + except psutil.NoSuchProcess: + pass + + def is_alive(self): + if not psutil.pid_exists(self._proc.pid): + return False + return self._proc.status() not in (psutil.STATUS_DEAD, psutil.STATUS_ZOMBIE) def is_ready(self): + if not self.is_alive(): + raise ParentNotAliveError() try: master = self.master worker = self.worker