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
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
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
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()
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
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)
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()
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()
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
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
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()
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()
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()
async def wait_for_interrupts() -> None: with trio.open_signal_receiver(signal.SIGINT, signal.SIGTERM) as stream: async for _ in stream: return
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
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()