Exemplo n.º 1
0
 async def run() -> None:
     with trio.open_signal_receiver(signal.SIGINT,
                                    signal.SIGTERM) as signal_aiter:
         async with _run_standalone_component(component_type,
                                              app_identifier):
             async for sig in signal_aiter:
                 return
Exemplo n.º 2
0
async def open_in_process(
    async_fn: Callable[..., TReturn], *args: Any
) -> AsyncIterator[Process[TReturn]]:
    proc = Process(async_fn, args)

    parent_r, child_w = os.pipe()
    child_r, parent_w = os.pipe()
    parent_pid = os.getpid()

    command = get_subprocess_command(child_r, child_w, parent_pid)

    sub_proc = await trio.open_process(
        command,
        # stdin=subprocess.PIPE,
        # stdout=subprocess.PIPE,
        # stderr=subprocess.PIPE,
        pass_fds=(child_r, child_w),
    )

    async with trio.open_nursery() as nursery:
        nursery.start_soon(_monitor_sub_proc, proc, sub_proc, parent_w)

        async with trio.hazmat.FdStream(parent_r) as from_child:
            with trio.open_signal_receiver(*RELAY_SIGNALS) as signal_aiter:
                # Monitor the child stream for incoming updates to the state of
                # the child process.
                nursery.start_soon(_monitor_state, proc, from_child)

                # Relay any appropriate signals to the child process.
                nursery.start_soon(_relay_signals, proc, signal_aiter)

                await proc.wait_pid()

                # Wait until the child process has reached the STARTED
                # state before yielding the context.  This ensures that any
                # calls to things like `terminate` or `kill` will be handled
                # properly in the child process.
                #
                # The timeout ensures that if something is fundamentally wrong
                # with the subprocess we don't hang indefinitely.
                with trio.fail_after(5):
                    await proc.wait_for_state(State.STARTED)

                try:
                    yield proc
                except KeyboardInterrupt as err:
                    # If a keyboard interrupt is encountered relay it to the
                    # child process and then give it a moment to cleanup before
                    # re-raising
                    try:
                        proc.send_signal(signal.SIGINT)
                        with trio.move_on_after(2):
                            await proc.wait()
                    finally:
                        raise err

                await proc.wait()

                nursery.cancel_scope.cancel()
async def handle_signals(exit_event):
    """Handle SIGINT / SIGTERM, setting the exit event"""
    with trio.open_signal_receiver(signal.SIGINT,
                                   signal.SIGTERM) as signal_handler:
        async for _ in signal_handler:
            exit_event.set()
            LOGGER.info("Exit signal received")
            return
Exemplo n.º 4
0
 async def run() -> None:
     component, connect_to_endpoints = _setup_standalone_component(
         component_type, app_identifier)
     with trio.open_signal_receiver(signal.SIGINT, signal.SIGTERM) as signal_aiter:
         async with _run_eventbus_for_component(component, connect_to_endpoints) as event_bus:
             async with _run_trio_component_in_proc(component, event_bus):
                 async for sig in signal_aiter:
                     return
Exemplo n.º 5
0
 async def _onterm(self):
     with trio.open_signal_receiver(signal.SIGTERM,
                                    signal.SIGINT) as signal_aiter:
         async for _ in signal_aiter:
             if self._nursery.cancel_scope.cancel_called:
                 raise KeyboardInterrupt()
             sdnotify.stopping()
             sdnotify.status("Terminating connections...")
             self._nursery.cancel_scope.cancel()
Exemplo n.º 6
0
 async def control_c_handler(nursery):
     with trio.open_signal_receiver(signal.SIGINT) as batched_signal_aiter:
         async for _ in batched_signal_aiter:
             print("\nAttempting graceful honeypot shutdown")
             nursery.cancel_scope.cancel()
             # We exit the loop, restoring the normal behavior of
             # control-C. This way hitting control-C once will try to
             # do a polite shutdown, but if that gets stuck the user
             # can hit control-C again to raise KeyboardInterrupt and
             # force things to exit.
             break
Exemplo n.º 7
0
Arquivo: dnslb.py Projeto: ebikt/dnslb
async def main() -> None:
    logger = Logger()
    sd_notifier = SDNotifier(logger=logger)
    with trio.open_signal_receiver(signal.SIGUSR1) as usr1:
        m: Optional[Main] = Main(True, sd_notifier, logger)
        await sd_notifier.notify(status="Starting.")
        if m is not None:
            if not await m.initialize():
                return
        while m is not None:
            m = await m.main(usr1)
Exemplo n.º 8
0
    async def parent():
        async with trio.open_nursery() as nursery:
            for mod in client.modules.keys():
                try:
                    nursery.start_soon(client.start_module, mod)
                finally:
                    print("Started: {}".format(mod))

            #clean shutdown
            with trio.open_signal_receiver(signal.SIGINT) as signal_aiter:
                async for signum in signal_aiter:
                    exit()
Exemplo n.º 9
0
 async def _do_run(cls, boot_info: BootInfo) -> None:
     event_bus_service = TrioEventBusService(
         boot_info.trinity_config,
         cls.get_endpoint_name(),
     )
     with trio.open_signal_receiver(signal.SIGINT,
                                    signal.SIGTERM) as signal_aiter:
         async with background_trio_service(event_bus_service):
             event_bus = await event_bus_service.get_event_bus()
             async with trio.open_nursery() as nursery:
                 nursery.start_soon(cls.do_run, boot_info, event_bus)
                 async for sig in signal_aiter:
                     nursery.cancel_scope.cancel()
Exemplo n.º 10
0
 async def _listen_for_shutdown_signals(self):
     """Listen for signals, potentially uniquely handling different signals, and initiating shutdown of event loops.
     """
     logger.debug(f'listening for shutdown signals')
     with trio.open_signal_receiver(signal.SIGINT, signal.SIGTERM, signal.SIGHUP) as signals:
         async for signal_number in signals:
             logger.debug(f'---- a shutdown signal has been received ----')
             if signal_number == signal.SIGINT:
                 logger.info(f'received SIGINT, running start_shutdown')
             elif signal_number == signal.SIGTERM:
                 logger.info(f'received SIGTERM, running start_shutdown')
             elif signal_number == signal.SIGHUP:
                 logger.info(f'received SIGHUP, running start_shutdown')
             self._start_shutdown()
             break
Exemplo n.º 11
0
async def _do_async_fn(
    async_fn: Callable[..., Awaitable[TReturn]],
    args: Sequence[Any],
    to_parent: BinaryIO,
) -> TReturn:
    with trio.open_signal_receiver(*SHUTDOWN_SIGNALS) as signal_aiter:
        update_state(to_parent, State.STARTED)

        async with trio.open_nursery() as nursery:
            nursery.start_soon(_do_monitor_signals, signal_aiter)

            update_state(to_parent, State.EXECUTING)

            result = await async_fn(*args)

            nursery.cancel_scope.cancel()
        return result
Exemplo n.º 12
0
    async def run(self) -> None:
        import signal  # noqa: F811
        import logging

        with trio.open_signal_receiver(signal.SIGTERM,
                                       signal.SIGINT) as signal_aiter:
            ready = trio.Event()
            self.manager.run_daemon_task(self._monitor_signals, ready,
                                         signal_aiter)
            # this is needed to give the async iterable time to be entered.
            await ready.wait()

            from alexandria.main import main
            await main()

            logger = logging.getLogger()
            logger.info('Stopping: Application Exited')
            self.manager.cancel()
Exemplo n.º 13
0
 async def _do_run(cls, boot_info: BootInfo) -> None:
     if cls.endpoint_name is None:
         endpoint_name = friendly_filename_or_url(cls.name)
     else:
         endpoint_name = cls.endpoint_name
     event_bus_service = TrioEventBusService(
         boot_info.trinity_config,
         endpoint_name,
     )
     with trio.open_signal_receiver(signal.SIGINT,
                                    signal.SIGTERM) as signal_aiter:
         async with background_trio_service(event_bus_service):
             await event_bus_service.wait_event_bus_available()
             event_bus = event_bus_service.get_event_bus()
             async with trio.open_nursery() as nursery:
                 nursery.start_soon(cls.do_run, boot_info, event_bus)
                 async for sig in signal_aiter:
                     nursery.cancel_scope.cancel()
Exemplo n.º 14
0
    async def run(self) -> None:
        import signal  # noqa: F811

        with trio.open_signal_receiver(signal.SIGTERM,
                                       signal.SIGINT) as signal_aiter:
            ready = trio.Event()
            self.manager.run_daemon_task(self._monitor_signals, ready,
                                         signal_aiter)
            # this is needed to give the async iterable time to be entered.
            await ready.wait()

            # imports are triggered at this stage.
            await _main()

            import logging

            logger = logging.getLogger("cthaeh")
            logger.info("Stopping: Application Exited")
            self.manager.cancel()
Exemplo n.º 15
0
async def wait_for_interrupts() -> None:
    with trio.open_signal_receiver(signal.SIGINT, signal.SIGTERM) as stream:
        async for _ in stream:
            return
Exemplo n.º 16
0
async def listen_for_shutdown_signals():
    with trio.open_signal_receiver(signal.SIGINT,
                                   signal.SIGTERM) as signal_aiter:
        async for sig in signal_aiter:
            gsm.start_shutdown()
            break
Exemplo n.º 17
0
    async def _open(self, async_fn: Callable[..., TReturn],
                    *args: Any) -> AsyncIterator[ProcessAPI[TReturn]]:
        if self._dead:
            raise Exception(f"Worker (pid={self.pid}) is no longer active")
        if self._busy:
            raise Exception(f"Worker (pid={self.pid}) is busy")
        self._busy = True
        proc: Process[TReturn] = Process(async_fn, args)
        proc.pid = self._trio_proc.pid
        async with trio.open_nursery() as nursery:
            # We write the execution data immediately without waiting for the
            # `WAIT_EXEC_DATA` state to ensure that the child process doesn't have
            # to wait for that data due to the round trip times between processes.
            logger.debug("Writing execution data for %s over stdin", proc)
            await self._to_child.send_all(proc.sub_proc_payload)

            startup_timeout = int(
                os.getenv(
                    "TRIO_RUN_IN_PROCESS_STARTUP_TIMEOUT",
                    constants.STARTUP_TIMEOUT_SECONDS,
                ))
            with trio.open_signal_receiver(*RELAY_SIGNALS) as signal_aiter:
                # Monitor the child stream for incoming updates to the state of
                # the child process.
                nursery.start_soon(_monitor_state, proc, self._from_child)

                # Relay any appropriate signals to the child process.
                nursery.start_soon(_relay_signals, proc, signal_aiter)

                try:
                    with trio.fail_after(startup_timeout):
                        await proc.wait_pid()
                except trio.TooSlowError:
                    proc.kill()
                    raise trio.TooSlowError(
                        f"{proc} took more than {startup_timeout} seconds to start up"
                    )

                # Wait until the child process has reached the EXECUTING
                # state before yielding the context.  This ensures that any
                # calls to things like `terminate` or `kill` will be handled
                # properly in the child process.
                #
                # The timeout ensures that if something is fundamentally wrong
                # with the subprocess we don't hang indefinitely.
                try:
                    with trio.fail_after(startup_timeout):
                        await proc.wait_for_state(State.EXECUTING)
                except trio.TooSlowError:
                    proc.kill()
                    raise trio.TooSlowError(
                        f"{proc} took more than {startup_timeout} seconds to start up"
                    )

                try:
                    try:
                        yield proc
                    except KeyboardInterrupt as err:
                        # If a keyboard interrupt is encountered relay it to the
                        # child process and then give it a moment to cleanup before
                        # re-raising
                        logger.debug(
                            "Got KeyboardInterrupt, sending SIGINT to %s",
                            proc)
                        try:
                            proc.send_signal(signal.SIGINT)
                            sigint_timeout = int(
                                os.getenv(
                                    "TRIO_RUN_IN_PROCESS_SIGINT_TIMEOUT",
                                    constants.SIGINT_TIMEOUT_SECONDS,
                                ))
                            try:
                                with trio.fail_after(sigint_timeout):
                                    await proc.wait()
                            except trio.TooSlowError:
                                logger.debug(
                                    "Timed out waiting for %s to exit after relaying SIGINT",
                                    proc,
                                )
                        finally:
                            raise err
                    else:
                        await proc.wait()
                finally:
                    if not proc._has_returncode.is_set():
                        # If the process has not returned at this stage we need to hard
                        # kill it to prevent it from hanging.
                        logger.warning(
                            "%s failed to exit cleanly.  Sending SIGKILL",
                            proc,
                            # The `any` call is to include a stacktrace if this
                            # happened due to an exception but to omit it if this is
                            # somehow happening outside of an exception context.
                            exc_info=any(sys.exc_info()),
                        )
                        proc.kill()
                    else:
                        logger.debug("process %s finished: returncode=%d",
                                     proc, proc.returncode)
                    self._busy = False
                    nursery.cancel_scope.cancel()