From b64c7595c8d95b2ec64b61b263f89fbfd5d021b7 Mon Sep 17 00:00:00 2001 From: karmacoma Date: Tue, 29 Oct 2024 17:56:04 -0700 Subject: [PATCH] implement parent monitoring thread fixes #7 --- src/jsi/cli.py | 36 ++++++++++++++++++++++++++++++++++++ src/jsi/server.py | 6 ++++-- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/jsi/cli.py b/src/jsi/cli.py index f0d9426..324551b 100644 --- a/src/jsi/cli.py +++ b/src/jsi/cli.py @@ -53,6 +53,7 @@ import signal import sys import threading +import time from functools import partial from jsi.config.loader import Config, find_available_solvers, load_definitions @@ -134,6 +135,38 @@ def cleanup(): atexit.register(cleanup) +def monitor_parent(): + """ + Monitor the parent process and exit if it dies or changes. + + Caveats: + - only works on POSIX systems + - only works if called early enough (before the original parent process exits) + """ + + parent_pid = os.getppid() + + def check_parent(): + while True: + try: + current_ppid = os.getppid() + + # if parent PID changed (original parent died), we exit + if current_ppid != parent_pid or current_ppid == 1: + stderr.print("parent process died, exiting...") + os.kill(os.getpid(), signal.SIGTERM) + break + time.sleep(1) # check every second + except ProcessLookupError: + # if we can't check parent PID, assume parent died + os.kill(os.getpid(), signal.SIGTERM) + break + + # Start monitoring in background thread + monitor_thread = threading.Thread(target=check_parent, daemon=True) + monitor_thread.start() + + class BadParameterError(Exception): pass @@ -229,6 +262,9 @@ def main(args: list[str] | None = None) -> int: global stdout global stderr + # kick off the parent monitor in the background as early as possible + monitor_parent() + if args is None: args = sys.argv[1:] diff --git a/src/jsi/server.py b/src/jsi/server.py index 60ea265..ea489e0 100644 --- a/src/jsi/server.py +++ b/src/jsi/server.py @@ -206,9 +206,11 @@ def sync_solve(self, file: str) -> str: listener = ResultListener() controller = ProcessController( - task, commands, self.config, + task, + commands, + self.config, start_callback=start_logger, - exit_callback=listener.exit_callback + exit_callback=listener.exit_callback, ) controller.start()