Ejemplo n.º 1
0
def kill_trinity_gracefully(trinity_config: TrinityConfig,
                            logger: logging.Logger,
                            processes: Iterable[multiprocessing.Process],
                            component_manager_service: ComponentManagerService,
                            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)
    component_manager_service.cancel_nowait()
    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)

    remove_dangling_ipc_files(logger, trinity_config.ipc_dir)

    ArgumentParser().exit(message=f"Trinity shutdown complete {hint}\n")
Ejemplo n.º 2
0
    def fix_unclean_shutdown(cls, args: Namespace,
                             trinity_config: TrinityConfig) -> None:
        logger = cls.get_logger()
        logger.info("Cleaning up unclean shutdown...")

        logger.info("Searching for process id files in %s..." %
                    trinity_config.data_dir)
        pidfiles = tuple(trinity_config.pid_dir.glob('*.pid'))
        if len(pidfiles) > 1:
            logger.info('Found %d processes from a previous run. Closing...' %
                        len(pidfiles))
        elif len(pidfiles) == 1:
            logger.info('Found 1 process from a previous run. Closing...')
        else:
            logger.info(
                'Found 0 processes from a previous run. No processes to kill.')

        for pidfile in pidfiles:
            process_id = int(pidfile.read_text())
            kill_process_id_gracefully(process_id, time.sleep, logger)
            try:
                pidfile.unlink()
                logger.info('Manually removed %s after killing process id %d' %
                            (pidfile, process_id))
            except FileNotFoundError:
                logger.debug(
                    'pidfile %s was gone after killing process id %d' %
                    (pidfile, process_id))

        remove_dangling_ipc_files(logger, trinity_config.ipc_dir)
Ejemplo n.º 3
0
def run(component_types: Tuple[Type[BaseComponentAPI], ...],
        boot_info: BootInfo, get_base_db_fn: Callable[[BootInfo],
                                                      LevelDB]) -> None:
    runtime_component_types = tuple(
        cast(Type[BaseIsolatedComponent], component_cls)
        for component_cls in component_types
        if issubclass(component_cls, ComponentAPI))

    trinity_config = boot_info.trinity_config

    component_manager_service = ComponentManager(
        boot_info,
        runtime_component_types,
    )
    component_manager_manager = AsyncioManager(component_manager_service)

    loop = asyncio.get_event_loop()
    loop.add_signal_handler(
        signal.SIGTERM,
        component_manager_manager.cancel,
        'SIGTERM',
    )
    loop.add_signal_handler(
        signal.SIGINT,
        component_manager_service.shutdown,
        'CTRL+C',
    )

    logger = logging.getLogger()
    try:
        loop.run_until_complete(
            _run(boot_info, get_base_db_fn, component_manager_manager))
    except BaseException:
        logger.exception("Error during trinity run")
        raise
    finally:
        reason = component_manager_service.reason
        hint = f" ({reason})" if reason else f""
        logger.info('Shutting down Trinity%s', hint)
        remove_dangling_ipc_files(logger, trinity_config.ipc_dir)
        argparse.ArgumentParser().exit(
            message=f"Trinity shutdown complete{hint}\n")
        if trinity_config.trinity_tmp_root_dir:
            shutil.rmtree(trinity_config.trinity_root_dir)