def loop( request, services, loop_debug, default_context, entrypoint_kwargs, thread_pool_size, thread_pool_executor, loop: asyncio.AbstractEventLoop, caplog: pytest.LogCaptureFixture, ): from aiomisc.context import get_context from aiomisc.entrypoint import entrypoint if LOG_LEVEL: LOG_LEVEL.set(logging.getLogger().getEffectiveLevel()) pool = thread_pool_executor(thread_pool_size) loop.set_default_executor(pool) get_marker = request.node.get_closest_marker forbid_loop_getter_marker = get_marker("forbid_get_event_loop") catch_unhandled_marker = get_marker("catch_loop_exceptions") exceptions = list() if catch_unhandled_marker: loop.set_exception_handler(lambda l, c: exceptions.append(c)) try: with entrypoint(*services, loop=loop, **entrypoint_kwargs): ctx = get_context(loop) for key, value in default_context.items(): ctx[key] = value if forbid_loop_getter_marker: asyncio.get_event_loop.side_effect = partial( pytest.fail, "get_event_loop is forbidden", ) yield loop if exceptions: logging.error( "Unhandled exceptions found:\n\n\t%s", "\n\t".join(("Message: {m}\n\t" "Future: {f}\n\t" "Exception: {e}").format( m=e["message"], f=repr(e.get("future")), e=repr(e.get("exception")), ) for e in exceptions), ) pytest.fail("Unhandled exceptions found. See logs.") finally: asyncio.get_event_loop.side_effect = get_event_loop del loop
async def executor(event_loop: asyncio.AbstractEventLoop): thread_pool = ThreadPoolExecutor(8, loop=event_loop) event_loop.set_default_executor(thread_pool) try: yield thread_pool finally: with suppress(Exception): thread_pool.shutdown(wait=True) event_loop.set_default_executor(None)
def executor(loop: asyncio.AbstractEventLoop): thread_pool = aiomisc.ThreadPoolExecutor(8) loop.set_default_executor(thread_pool) try: yield thread_pool finally: with suppress(Exception): thread_pool.shutdown(wait=True) thread_pool.shutdown(wait=True)
def run(self, event_loop: AbstractEventLoop = None): # Configure the logging system if isinstance(self.logging_config, dict): logging.config.dictConfig(self.logging_config) elif self.logging_config: logging.basicConfig(level=logging.INFO) # Assign a new default executor with the given max worker thread limit event_loop = event_loop or asyncio.get_event_loop() event_loop.set_default_executor(ThreadPoolExecutor(self.max_threads)) # Create the application context context = self.create_context() try: # Start all the components and run the loop until they've finished self.logger.info("Starting components") coroutines = (component.start(context) for component in self.components) coroutines = [coro for coro in coroutines if coro is not None] event_loop.run_until_complete(asyncio.gather(*coroutines)) self.logger.info("All components started") # Run the application's custom startup code coro = self.start(context) if coro is not None: event_loop.run_until_complete(coro) # Run all the application context's start callbacks event_loop.run_until_complete(context.run_callbacks(ContextEventType.started)) self.logger.info("Application started") except Exception as exc: self.logger.exception("Error during application startup") context.exception = exc else: # Finally, run the event loop until the process is terminated or Ctrl+C is pressed try: event_loop.run_forever() except (KeyboardInterrupt, SystemExit): pass event_loop.run_until_complete(context.run_callbacks(ContextEventType.finished)) event_loop.close() self.logger.info("Application stopped")