Beispiel #1
0
class TronDaemon(object):
    """Daemonize and run the tron daemon."""

    WAIT_SECONDS = 5

    def __init__(self, options):
        self.options = options
        self.mcp = None
        nodaemon = self.options.nodaemon
        context_class = NoDaemonContext if nodaemon else daemon.DaemonContext
        self.context = self._build_context(options, context_class)
        self.reactor = Reactor()

    def _build_context(self, options, context_class):
        signal_map = {
            signal.SIGHUP:  self._handle_reconfigure,
            signal.SIGINT:  self._handle_graceful_shutdown,
            signal.SIGTERM: self._handle_shutdown,
        }
        pidfile = PIDFile(options.pid_file)
        return context_class(
            working_directory=options.working_dir,
            umask=0o022,
            pidfile=pidfile,
            signal_map=signal_map,
            files_preserve=[pidfile.lock.file],
        )

    def run(self):
        with self.context:
            self.setup_reactor()
            setup_logging(self.options)
            self._run_mcp()
            self._run_www_api()
            self._run_reactor()

    def setup_reactor(self):
        installReactor(self.reactor)

    def _run_www_api(self):
        # Local import required because of reactor import in server and www
        from tron.api import resource
        site = resource.TronSite.create(self.mcp, self.options.web_path)
        port = self.options.listen_port
        self.reactor.listenTCP(port, site, interface=self.options.listen_host)

    def _run_mcp(self):
        # Local import required because of reactor import in mcp
        from tron import mcp
        working_dir = self.options.working_dir
        config_path = self.options.config_path
        self.mcp = mcp.MasterControlProgram(working_dir, config_path)

        try:
            self.mcp.initial_setup()
        except Exception as e:
            msg = "Error in configuration %s: %s"
            log.exception(msg % (config_path, e))
            raise

    def _run_reactor(self):
        """Run the twisted reactor."""
        self.reactor.run()

    def _handle_shutdown(self, sig_num, stack_frame):
        log.info("Shutdown requested: sig %s" % sig_num)
        if self.mcp:
            self.mcp.shutdown()
        self.reactor.stop()
        self.context.terminate(sig_num, stack_frame)

    def _handle_graceful_shutdown(self, sig_num, stack_frame):
        """Gracefully shutdown by waiting for Jobs to finish."""
        log.info("Graceful Shutdown requested: sig %s" % sig_num)
        if not self.mcp:
            self._handle_shutdown(sig_num, stack_frame)
            return
        self.mcp.graceful_shutdown()
        self._wait_for_jobs()

    def _wait_for_jobs(self):
        if self.mcp.jobs.is_shutdown:
            self._handle_shutdown(None, None)
            return

        log.info("Waiting for jobs to shutdown.")
        self.reactor.callLater(self.WAIT_SECONDS, self._wait_for_jobs)

    def _handle_reconfigure(self, _signal_number, _stack_frame):
        log.info("Reconfigure requested by SIGHUP.")
        self.reactor.callLater(0, self.mcp.reconfigure)