def trinity_boot( args: Namespace, trinity_config: TrinityConfig, extra_kwargs: Dict[str, Any], plugin_manager: PluginManager, listener: logging.handlers.QueueListener, main_endpoint: TrinityMainEventBusEndpoint, logger: logging.Logger) -> Tuple[multiprocessing.Process, ...]: # start the listener thread to handle logs produced by other processes in # the local logger. listener.start() ensure_eth1_dirs(trinity_config.get_app_config(Eth1AppConfig)) # First initialize the database process. database_server_process: multiprocessing.Process = ctx.Process( name="DB", target=run_database_process, args=( trinity_config, LevelDB, ), kwargs=extra_kwargs, ) networking_process: multiprocessing.Process = ctx.Process( name="networking", target=launch_node, args=( args, trinity_config, ), kwargs=extra_kwargs, ) # start the processes database_server_process.start() logger.info("Started DB server process (pid=%d)", database_server_process.pid) # networking process needs the IPC socket file provided by the database process try: wait_for_ipc(trinity_config.database_ipc_path) except TimeoutError as e: logger.error("Timeout waiting for database to start. Exiting...") kill_process_gracefully(database_server_process, logger) ArgumentParser().error(message="Timed out waiting for database start") return None networking_process.start() logger.info("Started networking process (pid=%d)", networking_process.pid) return (database_server_process, networking_process)
def trinity_boot(args: Namespace, trinity_config: TrinityConfig, extra_kwargs: Dict[str, Any], listener: logging.handlers.QueueListener, logger: logging.Logger) -> Tuple[multiprocessing.Process, ...]: # start the listener thread to handle logs produced by other processes in # the local logger. listener.start() ensure_beacon_dirs(trinity_config.get_app_config(BeaconAppConfig)) # First initialize the database process. database_server_process = ctx.Process( name="DB", target=run_database_process, args=( trinity_config, LevelDB, ), kwargs=extra_kwargs, ) # start the processes database_server_process.start() logger.info("Started DB server process (pid=%d)", database_server_process.pid) try: wait_for_ipc(trinity_config.database_ipc_path) except TimeoutError as e: logger.error("Timeout waiting for database to start. Exiting...") kill_process_gracefully(database_server_process, logger) ArgumentParser().error(message="Timed out waiting for database start") return None return (database_server_process,)
async def run(self) -> None: """ Call chain is: - multiprocessing.Process -> _run_process * isolates to a new process - _run_process -> run_process * sets up subprocess logging - run_process -> _do_run * runs the event loop and transitions into async context - _do_run -> do_run * sets up event bus and then enters user function. """ process = ctx.Process( target=self.run_process, args=(self._boot_info, ), ) loop = asyncio.get_event_loop() await loop.run_in_executor(None, process.start) try: await loop.run_in_executor(None, process.join) finally: kill_process_gracefully( process, get_logger('trinity.extensibility.TrioIsolatedComponent'), )
def trinity_boot(boot_info: BootInfo) -> Tuple[multiprocessing.Process]: trinity_config = boot_info.trinity_config ensure_eth1_dirs(trinity_config.get_app_config(Eth1AppConfig)) logger = logging.getLogger('trinity') # First initialize the database process. database_server_process: multiprocessing.Process = ctx.Process( name="DB", target=run_database_process, args=( boot_info, LevelDB, ), ) # start the processes database_server_process.start() logger.info("Started DB server process (pid=%d)", database_server_process.pid) # networking process needs the IPC socket file provided by the database process try: wait_for_ipc(trinity_config.database_ipc_path) except TimeoutError: logger.error("Timeout waiting for database to start. Exiting...") kill_process_gracefully(database_server_process, logger) ArgumentParser().error(message="Timed out waiting for database start") return None return (database_server_process,)
async def run(self) -> None: """ Call chain is: - multiprocessing.Process -> _run_process * isolates to a new process - _run_process -> run_process * sets up subprocess logging - run_process -> _do_run * runs the event loop and transitions into async context - _do_run -> do_run * sets up event bus and then enters user function. """ # FIXME: Use subprocess.Popen() so that we can make every process be its own process group # leader, like in AsyncioIsolatedComponent. process = ctx.Process( target=self.run_process, args=(self._boot_info, ), ) loop = asyncio.get_event_loop() await loop.run_in_executor(None, process.start) try: await loop.run_in_executor(None, process.join) finally: # XXX: Disabling this for now as our trio-based components currently run in the same # process group (see comment above) as the main process and because of that they # already get a SIGINT from the terminal. # kill_process_gracefully( # process, # get_logger('trinity.extensibility.TrioIsolatedComponent'), # ) pass
def start(self) -> None: """ Prepare the plugin to get started and eventually call ``do_start`` in a separate process. """ self._status = PluginStatus.STARTED self._process = ctx.Process(target=self._prepare_start, ) self._process.start() self.logger.info("Plugin started: %s", self.name)
def trinity_boot(args: Namespace, trinity_config: TrinityConfig, extra_kwargs: Dict[str, Any], plugin_manager: PluginManager, listener: logging.handlers.QueueListener, event_bus: EventBus, main_endpoint: Endpoint, logger: logging.Logger) -> None: # start the listener thread to handle logs produced by other processes in # the local logger. listener.start() event_bus.start() # First initialize the database process. database_server_process = ctx.Process( name="DB", target=run_database_process, args=( trinity_config, LevelDB, ), kwargs=extra_kwargs, ) # start the processes database_server_process.start() logger.info("Started DB server process (pid=%d)", database_server_process.pid) # networking process needs the IPC socket file provided by the database process try: wait_for_ipc(trinity_config.database_ipc_path) except TimeoutError as e: logger.error("Timeout waiting for database to start. Exiting...") kill_process_gracefully(database_server_process, logger) ArgumentParser().error(message="Timed out waiting for database start") def kill_trinity_with_reason(reason: str) -> None: kill_trinity_gracefully(logger, (database_server_process, ), plugin_manager, main_endpoint, event_bus, reason=reason) main_endpoint.subscribe(ShutdownRequest, lambda ev: kill_trinity_with_reason(ev.reason)) plugin_manager.prepare(args, trinity_config, extra_kwargs) kill_trinity_with_reason("No beacon support yet. SOON!") try: loop = asyncio.get_event_loop() loop.add_signal_handler(signal.SIGTERM, lambda: kill_trinity_with_reason("SIGTERM")) loop.run_forever() loop.close() except KeyboardInterrupt: kill_trinity_with_reason("CTRL+C / Keyboard Interrupt")
def start(self) -> None: """ Prepare the component to get started and eventually call ``do_start`` in a separate process. """ self._status = ComponentStatus.STARTED self._process = ctx.Process( target=self._prepare_spawn, ) self._process.start() self.logger.info("Component started: %s (pid=%d)", self.name, self._process.pid)
async def run(self) -> None: """ Call chain is: - multiprocessing.Process -> _run_process * isolates to a new process - _run_process -> run_process * sets up subprocess logging - run_process -> _do_run * runs the event loop and transitions into async context - _do_run -> do_run * sets up event bus and then enters user function. """ # FIXME: Use subprocess.Popen() so that we can make every process be its own process group # leader, like in AsyncioIsolatedComponent. process = ctx.Process( target=self.run_process, args=(self._boot_info, ), ) loop = asyncio.get_event_loop() await loop.run_in_executor(None, process.start) try: await loop.run_in_executor(None, process.join) finally: # NOTE: Since the subprocess we start here runs in the same process group as us (see # comment above as to why), when we get a Ctrl-C in the terminal the subprocess will # get it as well, so we first wait a fraction of SIGINT_TIMEOUT_SECONDS for it to # terminate (which is usually enough for trio to terminate all pending tasks), and # only if it hasn't finished by then we send it a SIGINT. If we send a SIGINT straight # away we cause trio to crash when we've been Ctrl-C'ed (because it would get two # SIGINTs), and if we don't send one at all the subprocess never terminates when # trinity exits because of a crash. self.logger.debug("Waiting for process %d to terminate", process.pid) await loop.run_in_executor(None, process.join, SIGINT_TIMEOUT_SECONDS / 4) if process.is_alive(): self.logger.debug( "Process %d did not terminate, sending SIGINT", process.pid) self._send_signal_and_join(process, signal.SIGINT, SIGINT_TIMEOUT_SECONDS) if process.is_alive(): self.logger.debug( "Process %d did not terminate, sending SIGTERM", process.pid) self._send_signal_and_join(process, signal.SIGTERM, SIGTERM_TIMEOUT_SECONDS)