Beispiel #1
0
def kill_helios_gracefully(logger: logging.Logger,
                           database_server_process: Any,
                           chain_processes: List[Any],
                           networking_process: Any,
                           plugin_manager: PluginManager,
                           main_endpoint: Endpoint,
                           event_bus: EventBus,
                           message: str="Helios 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), *[("Chain", chain_process) for chain_process in chain_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.
        if process is not None:
            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_helios_gracefully` so that
    # plugins can trigger a shutdown of the helios process.
    ArgumentParser().exit(message=message)
Beispiel #2
0
def setup_plugins(scope: BaseManagerProcessScope) -> PluginManager:
    plugin_manager = PluginManager(scope)
    # TODO: Implement auto-discovery of plugins based on some convention/configuration scheme
    plugin_manager.register(ENABLED_PLUGINS)

    return plugin_manager
Beispiel #3
0
def helios_boot(args: Namespace,
                chain_config: ChainConfig,
                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()

    networking_endpoint = event_bus.create_endpoint(NETWORKING_EVENTBUS_ENDPOINT)
    event_bus.start()

    # First initialize the database process.
    database_server_process = ctx.Process(
        target=run_database_process,
        args=(
            chain_config,
            LevelDB,
        ),
        kwargs=extra_kwargs,
    )

    chain_processes = []
    for i in range(chain_config.num_chain_processes):
        chain_process = ctx.Process(
            target=run_chain_process,
            args=(
                chain_config,
                i
            ),
            kwargs=extra_kwargs,
        )
        chain_processes.append(chain_process)


    networking_process = ctx.Process(
        target=launch_node,
        args=(args, chain_config, networking_endpoint,),
        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(chain_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")


    for i in range(chain_config.num_chain_processes):
        chain_process = chain_processes[i]
        chain_process.start()
        logger.info("Started chain instance {} process (pid={})".format(i,database_server_process.pid))
        try:
            wait_for_ipc(chain_config.get_chain_ipc_path(i))
        except TimeoutError as e:
            logger.error("Timeout waiting for chain instance {} to start.  Exiting...".format(i))
            kill_process_gracefully(database_server_process, logger)
            for j in range(i+1):
                kill_process_gracefully(chain_processes[j], logger)
            ArgumentParser().error(message="Timed out waiting for chain instance {} start".format(i))


    networking_process.start()
    logger.info("Started networking process (pid=%d)", networking_process.pid)

    main_endpoint.subscribe(
        ShutdownRequest,
        lambda ev: kill_helios_gracefully(
            logger,
            database_server_process,
            chain_processes,
            networking_process,
            plugin_manager,
            main_endpoint,
            event_bus
        )
    )

    plugin_manager.prepare(args, chain_config, extra_kwargs)
    plugin_manager.broadcast(HeliosStartupEvent(
        args,
        chain_config
    ))
    try:
        loop = asyncio.get_event_loop()
        loop.run_forever()
        loop.close()
    except KeyboardInterrupt:
        kill_helios_gracefully(
            logger,
            database_server_process,
            chain_processes,
            networking_process,
            plugin_manager,
            main_endpoint,
            event_bus
        )