def run(self, module_name): """Start the server and let it run until it's told to stop. Usually this must be the first method of this class that is called from its user. Parameter: module_name (str): the Python module name for the actual server implementation. Often identical to the directory name in which the implementation files are placed. Returns: values expected to be used as program's exit code. 0: server has run and finished successfully. 1: some error happens """ try: self.__module_name = module_name shutdown_sighandler = \ lambda signal, frame: self._trigger_shutdown() signal.signal(signal.SIGTERM, shutdown_sighandler) signal.signal(signal.SIGINT, shutdown_sighandler) self._setup_ccsession() self._setup_module() self._run_internal() logger.info(PYSERVER_COMMON_SERVER_STOPPED, self.__module_name) return 0 except BUNDYServerFatal as ex: logger.error(PYSERVER_COMMON_SERVER_FATAL, self.__module_name, ex) except Exception as ex: logger.error(PYSERVER_COMMON_UNCAUGHT_EXCEPTION, type(ex).__name__, ex) return 1
def _run_internal(self): """Main event loop. This method is essentially private, but allows tests to override it. """ logger.info(PYSERVER_COMMON_SERVER_STARTED, self.__module_name) cc_fileno = self._mod_cc.get_socket().fileno() while not self.__shutdown: try: read_fds = list(self._read_callbacks.keys()) read_fds.append(cc_fileno) write_fds = list(self._write_callbacks.keys()) error_fds = list(self._error_callbacks.keys()) (reads, writes, errors) = \ self._select_fn(read_fds, write_fds, error_fds) except select.error as ex: # ignore intterruption by signal; regard other select errors # fatal. if ex.args[0] == errno.EINTR: continue else: raise for fileno in reads: if fileno in self._read_callbacks: for callback in self._read_callbacks[fileno]: callback() for fileno in writes: if fileno in self._write_callbacks: for callback in self._write_callbacks[fileno]: callback() for fileno in errors: if fileno in self._error_callbacks: for callback in self._error_callbacks[fileno]: callback() if cc_fileno in reads: # this shouldn't raise an exception (if it does, we'll # propagate it) self._mod_cc.check_command(True) self._shutdown_module() self._mod_cc.send_stopping()