async def run_behaviors(self, behaviors: Tuple[BehaviorAPI, ...]) -> None: async with contextlib.AsyncExitStack() as stack: futures: List[asyncio.Task[Any]] = [ create_task(self.manager.wait_finished(), 'Connection/run_behaviors/wait_finished') ] for behavior in behaviors: if behavior.should_apply_to(self): behavior_exit = await stack.enter_async_context( behavior.apply(self)) futures.append(behavior_exit) self.behaviors_applied.set() # If wait_first() is called, cleanup_tasks() will be a no-op, but if any post_apply() # calls raise an exception, it will ensure we don't leak pending tasks that would # cause asyncio to complain. async with cleanup_tasks(*futures): try: for behavior in behaviors: behavior.post_apply() await wait_first(futures, max_wait_after_cancellation=2) except PeerConnectionLost: # Any of our behaviors may propagate a PeerConnectionLost, which is to be # expected as many Connection APIs used by them can raise that. To avoid a # DaemonTaskExit since we're returning silently, ensure we're cancelled. self.manager.cancel()
async def _do_run(self) -> None: with child_process_logging(self._boot_info): endpoint_name = self.get_endpoint_name() event_bus_service = AsyncioEventBusService( self._boot_info.trinity_config, endpoint_name, ) # FIXME: Must terminate component if event_bus_service terminates. async with background_asyncio_service(event_bus_service): event_bus = await event_bus_service.get_event_bus() loop_monitoring_task = create_task( self._loop_monitoring_task(event_bus), f'AsyncioIsolatedComponent/{self.name}/loop_monitoring_task' ) # FIXME: Must terminate component if loop_monitoring_task terminates. async with cleanup_tasks(loop_monitoring_task): try: if self._boot_info.profile: with profiler( f'profile_{self.get_endpoint_name()}'): await self.do_run(event_bus) else: # XXX: When open_in_process() injects a KeyboardInterrupt into us (via # coro.throw()), we hang forever here, until open_in_process() times # out and sends us a SIGTERM, at which point we exit without executing # either the except or the finally blocks below. # See https://github.com/ethereum/trinity/issues/1711 for more. await self.do_run(event_bus) except KeyboardInterrupt: # Currently we never reach this code path, but when we fix the issue above # it will be needed. return finally: # Once we start seeing this in the logs after a Ctrl-C, we'll likely have # figured out the issue above. self.logger.debug("%s: do_run() finished", self)