Ejemplo n.º 1
0
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)
Ejemplo n.º 2
0
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,)
Ejemplo n.º 3
0
    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'),
            )
Ejemplo n.º 4
0
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,)
Ejemplo n.º 5
0
    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
Ejemplo n.º 6
0
    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)
Ejemplo n.º 7
0
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")
Ejemplo n.º 8
0
    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)
Ejemplo n.º 9
0
    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)