import logging import os import time from multiprocessing import Process from django.conf import settings from django.db import connections from schedule import Scheduler from awx.main.dispatch.worker import TaskWorker logger = logging.getLogger('awx.main.dispatch.periodic') class Scheduler(Scheduler): def run_continuously(self): idle_seconds = max( 1, min(self.jobs).period.total_seconds() / 2 ) def run(): ppid = os.getppid() logger.warn('periodic beat started') while True: if os.getppid() != ppid: # if the parent PID changes, this process has been orphaned # via e.g., segfault or sigkill, we should exit too pid = os.getpid() logger.warn(f'periodic beat exiting gracefully pid:{pid}') raise SystemExit() try: for conn in connections.all(): # If the database connection has a hiccup, re-establish a new # connection conn.close_if_unusable_or_obsolete() self.run_pending() except Exception: logger.exception( 'encountered an error while scheduling periodic tasks' ) time.sleep(idle_seconds) process = Process(target=run) process.daemon = True process.start() def run_continuously(): scheduler = Scheduler() for task in settings.CELERYBEAT_SCHEDULE.values(): apply_async = TaskWorker.resolve_callable(task['task']).apply_async total_seconds = task['schedule'].total_seconds() scheduler.every(total_seconds).seconds.do(apply_async) scheduler.run_continuously()