def run(self): """ Run the Daemon. Setup signal handler, task registry, scheduler, listener and executors. Runs the main control loop. """ try: # setup signal handlers for shutdown or immediate termination signal(SIGINT, self.shutdown) signal(SIGTERM, self.terminate) registry.initialize() # create executors, listener and scheduler self.executor_pool = ThreadPool(1) self.scheduler = Scheduler(self.on_scheduled) self.listener = get_listener() self.scheduler.start() self.reload_schedule() while True: try: conn = self.listener.accept() except socket.error as exc: # connection closed if exc.errno in (errno.EINTR, errno.EBADF): logger.info( "Listener interrupted. Exiting main control loop." ) break else: raise command = None try: logger.debug("Client connected: %s", conn) message = conn.recv() logger.debug("Received message: %r", message) command = message[0] params = message[1:] if command == "reload": self.reload_schedule() elif command == "restart": job = models.Job.objects.get(id=params[0]) logger.info("Restarting job '%s'" % job) self.executor_pool.apply_async( registry.run, [job], job.arguments ) elif command == "abort": pass # TODO: implement except Exception as exc: logger.exception("Daemon command %s failed." % command) finally: self.shutdown()
class Daemon(object): """ Multi-purpose task management daemon. """ def __init__(self): self.scheduler = None self.listener = None self.executor_pool = None def run(self): """ Run the Daemon. Setup signal handler, task registry, scheduler, listener and executors. Runs the main control loop. """ try: # setup signal handlers for shutdown or immediate termination signal(SIGINT, self.shutdown) signal(SIGTERM, self.terminate) registry.initialize() # create executors, listener and scheduler self.executor_pool = ThreadPool(1) self.scheduler = Scheduler(self.on_scheduled) self.listener = get_listener() self.scheduler.start() self.reload_schedule() while True: try: conn = self.listener.accept() except socket.error as exc: # connection closed if exc.errno in (errno.EINTR, errno.EBADF): logger.info( "Listener interrupted. Exiting main control loop." ) break else: raise command = None try: logger.debug("Client connected: %s", conn) message = conn.recv() logger.debug("Received message: %r", message) command = message[0] params = message[1:] if command == "reload": self.reload_schedule() elif command == "restart": job = models.Job.objects.get(id=params[0]) logger.info("Restarting job '%s'" % job) self.executor_pool.apply_async( registry.run, [job], job.arguments ) elif command == "abort": pass # TODO: implement except Exception as exc: logger.exception("Daemon command %s failed." % command) finally: self.shutdown() def shutdown(self, signum=None, frame=None, terminate=False): """ Shutdown method. When ``terminate`` is ``True``, then the underlying pool is terminated. Otherwise, running tasks are finished. """ if self.executor_pool: if terminate: self.executor_pool.terminate() else: self.executor_pool.close() if self.scheduler: self.scheduler.shutdown() self.scheduler = None if self.listener: self.listener.close() self.listener = None def terminate(self, signum=None, frame=None): self.shutdown(terminate=True) def on_scheduled(self, scheduled_task): task = scheduled_task.task arguments = scheduled_task.argument_values scheduled_task.delete() print task, arguments self.executor_pool.apply_async(run_task, [task], arguments) def reload_schedule(self): """ Reload the scheduled items from the database. """ self.scheduler.reset() for scheduled_task in models.ScheduledJob.objects.all(): self.scheduler.schedule(scheduled_task.when, [scheduled_task])