From 2c6a4583d001528002b02e71bbf01586c3671007 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Louis=20V=C3=A9zina?= <5130500+morpheus65535@users.noreply.github.com> Date: Tue, 14 Apr 2020 22:20:23 -0400 Subject: [PATCH] Simplify daemon mechanism. --- bazarr.py | 166 ++++++++++++----------------------------------- views/system.tpl | 19 ++---- 2 files changed, 47 insertions(+), 138 deletions(-) diff --git a/bazarr.py b/bazarr.py index 9466fbd02..30aa26755 100644 --- a/bazarr.py +++ b/bazarr.py @@ -2,28 +2,25 @@ import os import platform -import signal import subprocess import sys import time +import atexit from bazarr.get_args import args -from libs.six import PY3 def check_python_version(): python_version = platform.python_version_tuple() - minimum_py2_tuple = (2, 7, 13) minimum_py3_tuple = (3, 7, 0) - minimum_py2_str = ".".join(str(i) for i in minimum_py2_tuple) minimum_py3_str = ".".join(str(i) for i in minimum_py3_tuple) - if int(python_version[0]) < 3: + if int(python_version[0]) < minimum_py3_tuple[0]: print("Python " + minimum_py3_str + " or greater required. " "Current version is " + platform.python_version() + ". Please upgrade Python.") sys.exit(1) elif (int(python_version[0]) == minimum_py3_tuple[0] and int(python_version[1]) < minimum_py3_tuple[1]) or \ - (int(python_version[0]) != minimum_py3_tuple[0] and int(python_version[0]) != minimum_py2_tuple[0]): + (int(python_version[0]) != minimum_py3_tuple[0]): print("Python " + minimum_py3_str + " or greater required. " "Current version is " + platform.python_version() + ". Please upgrade Python.") sys.exit(1) @@ -34,138 +31,55 @@ check_python_version() dir_name = os.path.dirname(__file__) -class ProcessRegistry: - - def register(self, process): - pass - - def unregister(self, process): - pass - - -class DaemonStatus(ProcessRegistry): - - def __init__(self): - self.__should_stop = False - self.__processes = set() - - def register(self, process): - self.__processes.add(process) - - def unregister(self, process): - self.__processes.remove(process) - - @staticmethod - def __send_signal(processes, signal_no, live_processes=None): - """ - Sends to every single of the specified processes the given signal and (if live_processes is not None) append to - it processes which are still alive. - """ - for ep in processes: - if ep.poll() is None: - if live_processes is not None: - live_processes.append(ep) - try: - ep.send_signal(signal_no) - except Exception as e: - print('Failed sending signal %s to process %s because of an unexpected error: %s' % ( - signal_no, ep.pid, e)) - return live_processes - - def stop(self): - """ - Flags this instance as should stop and terminates as smoothly as possible children processes. - """ - self.__should_stop = True - DaemonStatus.__send_signal(self.__processes, signal.SIGINT, list()) - - def force_stop(self): - self.__should_stop = True - DaemonStatus.__send_signal(self.__processes, signal.SIGTERM) - - def should_stop(self): - return self.__should_stop - - -def start_bazarr(process_registry=ProcessRegistry()): +def start_bazarr(): script = [sys.executable, "-u", os.path.normcase(os.path.join(dir_name, 'bazarr', 'main.py'))] + sys.argv[1:] - - print("Bazarr starting...") - if PY3: - ep = subprocess.Popen(script, stdout=None, stderr=None, stdin=subprocess.DEVNULL) - else: - ep = subprocess.Popen(script, stdout=None, stderr=None, stdin=None) - process_registry.register(ep) - try: - ep.wait() - process_registry.unregister(ep) - except KeyboardInterrupt: - pass + ep = subprocess.Popen(script, stdout=None, stderr=None, stdin=subprocess.DEVNULL) + atexit.register(lambda: ep.kill()) + + +def check_status(): + if os.path.exists(stopfile): + try: + os.remove(stopfile) + except Exception: + print('Unable to delete stop file.') + finally: + print('Bazarr exited.') + sys.exit(0) + + if os.path.exists(restartfile): + try: + os.remove(restartfile) + except Exception: + print('Unable to delete restart file.') + else: + print("Bazarr is restarting...") + start_bazarr() if __name__ == '__main__': - restartfile = os.path.normcase(os.path.join(args.config_dir, 'bazarr.restart')) - stopfile = os.path.normcase(os.path.join(args.config_dir, 'bazarr.stop')) + restartfile = os.path.join(args.config_dir, 'bazarr.restart') + stopfile = os.path.join(args.config_dir, 'bazarr.stop') + # Cleanup leftover files try: os.remove(restartfile) - except Exception: + except FileNotFoundError: pass try: os.remove(stopfile) - except Exception: + except FileNotFoundError: pass - - def daemon(bazarr_runner=lambda: start_bazarr()): - if os.path.exists(stopfile): - try: - os.remove(stopfile) - except Exception: - print('Unable to delete stop file.') - else: - print('Bazarr exited.') - sys.exit(0) - - if os.path.exists(restartfile): - try: - os.remove(restartfile) - except Exception: - print('Unable to delete restart file.') - else: - bazarr_runner() - - - bazarr_runner = lambda: start_bazarr() - - should_stop = lambda: False - - if PY3: - daemonStatus = DaemonStatus() - - def force_shutdown(): - # force the killing of children processes - daemonStatus.force_stop() - # if a new SIGTERM signal is caught the standard behaviour should be followed - signal.signal(signal.SIGTERM, signal.SIG_DFL) - # emulate a Ctrl C command on itself (bypasses the signal thing but, then, emulates the "Ctrl+C break") - os.kill(os.getpid(), signal.SIGINT) - - def shutdown(): - # indicates that everything should stop - daemonStatus.stop() - # if a new sigterm signal is caught it should force the shutdown of children processes - signal.signal(signal.SIGTERM, lambda signal_no, frame: force_shutdown()) - - signal.signal(signal.SIGTERM, lambda signal_no, frame: shutdown()) - - should_stop = lambda: daemonStatus.should_stop() - bazarr_runner = lambda: start_bazarr(daemonStatus) - - bazarr_runner() + # Initial start of main bazarr process + print("Bazarr starting...") + start_bazarr() # Keep the script running forever until stop is requested through term or keyboard interrupt - while not should_stop(): - daemon(bazarr_runner) - time.sleep(1) + while True: + check_status() + try: + time.sleep(1) + except (KeyboardInterrupt, SystemExit): + pass diff --git a/views/system.tpl b/views/system.tpl index e3a04ca81..dd73ba382 100644 --- a/views/system.tpl +++ b/views/system.tpl @@ -403,15 +403,12 @@ }); $('#shutdown').on('click', function(){ - $.ajax({ - url: "{{base_url}}shutdown", - async: false + document.open(); + document.write('Bazarr has shutdown.'); + document.close(); + $.ajax({ + url: "{{base_url}}shutdown" }) - .always(function(){ - document.open(); - document.write('Bazarr has shutdown.'); - document.close(); - }); }); $('#logout').on('click', function(){ @@ -422,11 +419,9 @@ $('#loader_text').text("Bazarr is restarting, please wait..."); $.ajax({ url: "{{base_url}}restart", - async: true, - error: (function () { - setTimeout(function () { setInterval(ping, 2000); }, 8000); - }) + async: true }); + setTimeout(function () { setInterval(ping, 2000); }, 8000); }); % from config import settings