async def handle_networking_exit(service: BaseService, plugin_manager: PluginManager, endpoint: Endpoint) -> None: async with exit_signal_with_service(service): await plugin_manager.shutdown() endpoint.stop()
def kill_trinity_gracefully(logger: logging.Logger, database_server_process: Any, networking_process: Any, plugin_manager: PluginManager, main_endpoint: Endpoint, event_bus: EventBus, message: str="Trinity shudown complete\n") -> None: # When a user hits Ctrl+C in the terminal, the SIGINT is sent to all processes in the # foreground *process group*, so both our networking and database processes will terminate # at the same time and not sequentially as we'd like. That shouldn't be a problem but if # we keep getting unhandled BrokenPipeErrors/ConnectionResetErrors like reported in # https://github.com/ethereum/py-evm/issues/827, we might want to change the networking # process' signal handler to wait until the DB process has terminated before doing its # thing. # Notice that we still need the kill_process_gracefully() calls here, for when the user # simply uses 'kill' to send a signal to the main process, but also because they will # perform a non-gracefull shutdown if the process takes too long to terminate. logger.info('Keyboard Interrupt: Stopping') plugin_manager.shutdown_blocking() main_endpoint.stop() event_bus.stop() for name, process in [("DB", database_server_process), ("Networking", networking_process)]: # Our sub-processes will have received a SIGINT already (see comment above), so here we # wait 2s for them to finish cleanly, and if they fail we kill them for real. process.join(2) if process.is_alive(): kill_process_gracefully(process, logger) logger.info('%s process (pid=%d) terminated', name, process.pid) # This is required to be within the `kill_trinity_gracefully` so that # plugins can trigger a shutdown of the trinity process. ArgumentParser().exit(message=message)
def kill_trinity_gracefully(logger: logging.Logger, processes: Iterable[multiprocessing.Process], plugin_manager: PluginManager, main_endpoint: Endpoint, event_bus: EventBus, reason: str = None) -> None: # When a user hits Ctrl+C in the terminal, the SIGINT is sent to all processes in the # foreground *process group*, so both our networking and database processes will terminate # at the same time and not sequentially as we'd like. That shouldn't be a problem but if # we keep getting unhandled BrokenPipeErrors/ConnectionResetErrors like reported in # https://github.com/ethereum/py-evm/issues/827, we might want to change the networking # process' signal handler to wait until the DB process has terminated before doing its # thing. # Notice that we still need the kill_process_gracefully() calls here, for when the user # simply uses 'kill' to send a signal to the main process, but also because they will # perform a non-gracefull shutdown if the process takes too long to terminate. hint = f"({reason})" if reason else f"" logger.info('Shutting down Trinity %s', hint) plugin_manager.shutdown_blocking() main_endpoint.stop() event_bus.stop() for process in processes: # Our sub-processes will have received a SIGINT already (see comment above), so here we # wait 2s for them to finish cleanly, and if they fail we kill them for real. process.join(2) if process.is_alive(): kill_process_gracefully(process, logger) logger.info('%s process (pid=%d) terminated', process.name, process.pid) ArgumentParser().exit(message=f"Trinity shutdown complete {hint}\n")
async def handle_networking_exit(service: BaseService, plugin_manager: PluginManager, endpoint: Endpoint) -> None: async with exit_signal_with_service(service): await plugin_manager.shutdown() endpoint.stop() # Retrieve and shutdown the global executor that was created at startup ensure_global_asyncio_executor().shutdown(wait=True)
async def exit_on_signal(service_to_exit: BaseService, endpoint: Endpoint = None) -> None: loop = service_to_exit.get_event_loop() sigint_received = asyncio.Event() for sig in [signal.SIGINT, signal.SIGTERM]: # TODO also support Windows loop.add_signal_handler(sig, sigint_received.set) await sigint_received.wait() try: await service_to_exit.cancel() if endpoint is not None: endpoint.stop() service_to_exit._executor.shutdown(wait=True) finally: loop.stop()
async def exit_with_service_and_endpoint(service_to_exit: BaseService, endpoint: Endpoint) -> None: async with exit_signal_with_service(service_to_exit): endpoint.stop()