mirror of https://github.com/morpheus65535/bazarr
Refactor shutdown / restart code
- centralize and simplify code - eliminate code duplication - hide unnecessary details from rest of code by abstraction - standardize exit codes - shorten shutdown / restart time - improve console messaging
This commit is contained in:
parent
65622196b7
commit
5d01d54dab
59
bazarr.py
59
bazarr.py
|
@ -9,7 +9,11 @@ import time
|
|||
import atexit
|
||||
|
||||
from bazarr.app.get_args import args
|
||||
from bazarr.literals import *
|
||||
|
||||
def exit_program(status_code):
|
||||
print(f'Bazarr exited with status code {status_code}.')
|
||||
raise SystemExit(status_code)
|
||||
|
||||
def check_python_version():
|
||||
python_version = platform.python_version_tuple()
|
||||
|
@ -19,7 +23,7 @@ def check_python_version():
|
|||
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)
|
||||
exit_program(EXIT_PYTHON_UPGRADE_NEEDED)
|
||||
elif int(python_version[0]) == 3 and int(python_version[1]) > 11:
|
||||
print("Python version greater than 3.11.x is unsupported. Current version is " + platform.python_version() +
|
||||
". Keep in mind that even if it works, you're on your own.")
|
||||
|
@ -27,7 +31,7 @@ def check_python_version():
|
|||
(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)
|
||||
exit_program(EXIT_PYTHON_UPGRADE_NEEDED)
|
||||
|
||||
|
||||
def get_python_path():
|
||||
|
@ -73,31 +77,57 @@ def start_bazarr():
|
|||
ep = subprocess.Popen(script, stdout=None, stderr=None, stdin=subprocess.DEVNULL)
|
||||
atexit.register(end_child_process, ep=ep)
|
||||
signal.signal(signal.SIGTERM, lambda signal_no, frame: end_child_process(ep))
|
||||
print(f"Bazarr starting child process with PID {ep.pid}...")
|
||||
return ep
|
||||
|
||||
|
||||
def get_stop_status_code(input_file):
|
||||
try:
|
||||
with open(input_file,'r') as file:
|
||||
# read status code from file, if it exists
|
||||
line = file.readline()
|
||||
try:
|
||||
status_code = int(line)
|
||||
except (ValueError, TypeError):
|
||||
status_code = EXIT_NORMAL
|
||||
file.close()
|
||||
except:
|
||||
status_code = EXIT_NORMAL
|
||||
return status_code
|
||||
|
||||
|
||||
def check_status():
|
||||
global child_process
|
||||
if os.path.exists(stopfile):
|
||||
status_code = get_stop_status_code(stopfile)
|
||||
try:
|
||||
print(f"Deleting stop file...")
|
||||
os.remove(stopfile)
|
||||
except Exception:
|
||||
except Exception as e:
|
||||
print('Unable to delete stop file.')
|
||||
finally:
|
||||
print('Bazarr exited.')
|
||||
sys.exit(0)
|
||||
print(f"Terminating child process with PID {child_process.pid}")
|
||||
child_process.terminate()
|
||||
exit_program(status_code)
|
||||
|
||||
if os.path.exists(restartfile):
|
||||
try:
|
||||
print(f"Deleting restart file...")
|
||||
os.remove(restartfile)
|
||||
except Exception:
|
||||
print('Unable to delete restart file.')
|
||||
else:
|
||||
print("Bazarr is restarting...")
|
||||
start_bazarr()
|
||||
finally:
|
||||
print(f"Terminating child process with PID {child_process.pid}")
|
||||
child_process.terminate()
|
||||
print(f"Bazarr is restarting...")
|
||||
child_process = start_bazarr()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
restartfile = os.path.join(args.config_dir, 'bazarr.restart')
|
||||
stopfile = os.path.join(args.config_dir, 'bazarr.stop')
|
||||
restartfile = os.path.join(args.config_dir, FILE_RESTART)
|
||||
stopfile = os.path.join(args.config_dir, FILE_STOP)
|
||||
os.environ[ENV_STOPFILE] = stopfile
|
||||
os.environ[ENV_RESTARTFILE] = restartfile
|
||||
|
||||
# Cleanup leftover files
|
||||
try:
|
||||
|
@ -111,10 +141,9 @@ if __name__ == '__main__':
|
|||
pass
|
||||
|
||||
# Initial start of main bazarr process
|
||||
print("Bazarr starting...")
|
||||
start_bazarr()
|
||||
child_process = start_bazarr()
|
||||
|
||||
# Keep the script running forever until stop is requested through term or keyboard interrupt
|
||||
# Keep the script running forever until stop is requested through term, special files or keyboard interrupt
|
||||
while True:
|
||||
check_status()
|
||||
try:
|
||||
|
@ -124,5 +153,5 @@ if __name__ == '__main__':
|
|||
os.wait()
|
||||
time.sleep(1)
|
||||
except (KeyboardInterrupt, SystemExit, ChildProcessError):
|
||||
print('Bazarr exited.')
|
||||
sys.exit(0)
|
||||
print(f'Bazarr exited main script file via keyboard interrupt.')
|
||||
exit_program(EXIT_NORMAL)
|
||||
|
|
|
@ -6,6 +6,8 @@ import ast
|
|||
import logging
|
||||
|
||||
from urllib.parse import quote_plus
|
||||
from literals import EXIT_VALIDATION_ERROR
|
||||
from utilities.central import stop_bazarr
|
||||
from subliminal.cache import region
|
||||
from dynaconf import Dynaconf, Validator as OriginalValidator
|
||||
from dynaconf.loaders.yaml_loader import write
|
||||
|
@ -393,8 +395,9 @@ while failed_validator:
|
|||
settings[current_validator_details.names[0]] = current_validator_details.default
|
||||
else:
|
||||
logging.critical(f"Value for {current_validator_details.names[0]} doesn't pass validation and there's no "
|
||||
f"default value. This issue must be reported. Bazarr won't works until it's been fixed.")
|
||||
os._exit(0)
|
||||
f"default value. This issue must be reported to and fixed by the development team. "
|
||||
f"Bazarr won't work until it's been fixed.")
|
||||
stop_bazarr(EXIT_VALIDATION_ERROR)
|
||||
|
||||
|
||||
def write_config():
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
import warnings
|
||||
import logging
|
||||
import os
|
||||
import io
|
||||
import errno
|
||||
from literals import EXIT_NORMAL
|
||||
from utilities.central import restart_bazarr, stop_bazarr
|
||||
|
||||
from waitress.server import create_server
|
||||
from time import sleep
|
||||
|
@ -72,31 +72,19 @@ class Server:
|
|||
except Exception:
|
||||
pass
|
||||
|
||||
def close_all(self):
|
||||
print(f"Closing database...")
|
||||
close_database()
|
||||
print(f"Closing webserver...")
|
||||
self.server.close()
|
||||
|
||||
def shutdown(self):
|
||||
try:
|
||||
stop_file = io.open(os.path.join(args.config_dir, "bazarr.stop"), "w", encoding='UTF-8')
|
||||
except Exception as e:
|
||||
logging.error(f'BAZARR Cannot create stop file: {repr(e)}')
|
||||
else:
|
||||
logging.info('Bazarr is being shutdown...')
|
||||
stop_file.write(str(''))
|
||||
stop_file.close()
|
||||
close_database()
|
||||
self.server.close()
|
||||
os._exit(0)
|
||||
self.close_all()
|
||||
stop_bazarr(EXIT_NORMAL, False)
|
||||
|
||||
def restart(self):
|
||||
try:
|
||||
restart_file = io.open(os.path.join(args.config_dir, "bazarr.restart"), "w", encoding='UTF-8')
|
||||
except Exception as e:
|
||||
logging.error(f'BAZARR Cannot create restart file: {repr(e)}')
|
||||
else:
|
||||
logging.info('Bazarr is being restarted...')
|
||||
restart_file.write(str(''))
|
||||
restart_file.close()
|
||||
close_database()
|
||||
self.server.close()
|
||||
os._exit(0)
|
||||
self.close_all()
|
||||
restart_bazarr()
|
||||
|
||||
|
||||
webserver = Server()
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
# coding=utf-8
|
||||
|
||||
import os
|
||||
import io
|
||||
import sys
|
||||
import subprocess
|
||||
import subliminal
|
||||
|
@ -20,6 +19,9 @@ from utilities.backup import restore_from_backup
|
|||
|
||||
from app.database import init_db
|
||||
|
||||
from literals import *
|
||||
from utilities.central import make_bazarr_dir, restart_bazarr, stop_bazarr
|
||||
|
||||
# set start time global variable as epoch
|
||||
global startTime
|
||||
startTime = time.time()
|
||||
|
@ -37,20 +39,15 @@ if not os.path.exists(args.config_dir):
|
|||
os.mkdir(os.path.join(args.config_dir))
|
||||
except OSError:
|
||||
print("BAZARR The configuration directory doesn't exist and Bazarr cannot create it (permission issue?).")
|
||||
exit(2)
|
||||
stop_bazarr(EXIT_CONFIG_CREATE_ERROR)
|
||||
|
||||
if not os.path.exists(os.path.join(args.config_dir, 'config')):
|
||||
os.mkdir(os.path.join(args.config_dir, 'config'))
|
||||
if not os.path.exists(os.path.join(args.config_dir, 'db')):
|
||||
os.mkdir(os.path.join(args.config_dir, 'db'))
|
||||
if not os.path.exists(os.path.join(args.config_dir, 'log')):
|
||||
os.mkdir(os.path.join(args.config_dir, 'log'))
|
||||
if not os.path.exists(os.path.join(args.config_dir, 'cache')):
|
||||
os.mkdir(os.path.join(args.config_dir, 'cache'))
|
||||
if not os.path.exists(os.path.join(args.config_dir, 'backup')):
|
||||
os.mkdir(os.path.join(args.config_dir, 'backup'))
|
||||
if not os.path.exists(os.path.join(args.config_dir, 'restore')):
|
||||
os.mkdir(os.path.join(args.config_dir, 'restore'))
|
||||
os.environ[ENV_BAZARR_ROOT_DIR] = os.path.join(args.config_dir)
|
||||
make_bazarr_dir(DIR_BACKUP)
|
||||
make_bazarr_dir(DIR_CACHE)
|
||||
make_bazarr_dir(DIR_CONFIG)
|
||||
make_bazarr_dir(DIR_DB)
|
||||
make_bazarr_dir(DIR_LOG)
|
||||
make_bazarr_dir(DIR_RESTORE)
|
||||
|
||||
# set subliminal_patch hearing-impaired extension to use when naming subtitles
|
||||
os.environ["SZ_HI_EXTENSION"] = settings.general.hi_extension
|
||||
|
@ -99,19 +96,20 @@ if not args.no_update:
|
|||
subprocess.check_output(pip_command, stderr=subprocess.STDOUT)
|
||||
except subprocess.CalledProcessError as e:
|
||||
logging.exception(f'BAZARR requirements.txt installation result: {e.stdout}')
|
||||
os._exit(1)
|
||||
os._exit(EXIT_REQUIREMENTS_ERROR)
|
||||
else:
|
||||
logging.info('BAZARR requirements installed.')
|
||||
|
||||
try:
|
||||
restart_file = io.open(os.path.join(args.config_dir, "bazarr.restart"), "w", encoding='UTF-8')
|
||||
except Exception as e:
|
||||
logging.error(f'BAZARR Cannot create restart file: {repr(e)}')
|
||||
else:
|
||||
logging.info('Bazarr is being restarted...')
|
||||
restart_file.write(str(''))
|
||||
restart_file.close()
|
||||
os._exit(0)
|
||||
restart_bazarr()
|
||||
# try:
|
||||
# restart_file = io.open(get_restart_file_path(), "w", encoding='UTF-8')
|
||||
# except Exception as e:
|
||||
# logging.error(f'BAZARR Cannot create restart file: {repr(e)}')
|
||||
# else:
|
||||
# logging.info('Bazarr is being restarted...')
|
||||
# restart_file.write(str(''))
|
||||
# restart_file.close()
|
||||
# os._exit(0)
|
||||
|
||||
# change default base_url to ''
|
||||
settings.general.base_url = settings.general.base_url.rstrip('/')
|
||||
|
|
|
@ -42,16 +42,8 @@ from app.server import webserver, app # noqa E402
|
|||
from app.announcements import get_announcements_to_file # noqa E402
|
||||
|
||||
if args.create_db_revision:
|
||||
try:
|
||||
stop_file = io.open(os.path.join(args.config_dir, "bazarr.stop"), "w", encoding='UTF-8')
|
||||
except Exception as e:
|
||||
logging.error(f'BAZARR Cannot create stop file: {repr(e)}')
|
||||
else:
|
||||
create_db_revision(app)
|
||||
logging.info('Bazarr is being shutdown...')
|
||||
stop_file.write(str(''))
|
||||
stop_file.close()
|
||||
os._exit(0)
|
||||
create_db_revision(app)
|
||||
stop_bazarr(EXIT_NORMAL)
|
||||
else:
|
||||
migrate_db(app)
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
# coding=utf-8
|
||||
|
||||
import os
|
||||
import io
|
||||
import sqlite3
|
||||
import shutil
|
||||
import logging
|
||||
|
@ -12,6 +11,7 @@ from glob import glob
|
|||
|
||||
from app.get_args import args
|
||||
from app.config import settings
|
||||
from utilities.central import restart_bazarr
|
||||
|
||||
|
||||
def get_backup_path():
|
||||
|
@ -133,16 +133,7 @@ def restore_from_backup():
|
|||
logging.exception(f'Unable to delete {dest_database_path}')
|
||||
|
||||
logging.info('Backup restored successfully. Bazarr will restart.')
|
||||
|
||||
try:
|
||||
restart_file = io.open(os.path.join(args.config_dir, "bazarr.restart"), "w", encoding='UTF-8')
|
||||
except Exception as e:
|
||||
logging.error(f'BAZARR Cannot create restart file: {repr(e)}')
|
||||
else:
|
||||
logging.info('Bazarr is being restarted...')
|
||||
restart_file.write('')
|
||||
restart_file.close()
|
||||
os._exit(0)
|
||||
restart_bazarr()
|
||||
elif os.path.isfile(restore_config_path) or os.path.isfile(restore_database_path):
|
||||
logging.debug('Cannot restore a partial backup. You must have both config and database.')
|
||||
else:
|
||||
|
|
Loading…
Reference in New Issue