From 44cc695d883a23a65f95141b240837cbb57c1fa2 Mon Sep 17 00:00:00 2001 From: Florian Scherf Date: Sat, 3 Feb 2024 22:28:59 +0100 Subject: [PATCH] tests: server: incompatibility with aiohttp 3.9 Previously, the test suite repeatedly crashed in CI when running tests that involved a browser disconnecting unexpectedly, such as the channels or bucket tests. Seemingly, this started with the release of aiohttp 3.9 which introduced web handler cancellation. https://docs.aiohttp.org/en/v3.9.0/web_advanced.html#web-handler-cancellation Web handler cancellation means that aiohttp cancels the asyncio tasks of aiohttp request handlers which encounter a `ConnectionClosedError`. In Lona, the teardown code for connections gets called within aiohttp request handlers, meaning that sometimes the connection teardown code does not run. Web handler cancellation is an opt-in feature that is not enabled by default, nor is it enabled by Lona. Although, it is enabled by pytest-aiohttp, which is the reason it only crashes in CI. As proposed in the aiohttp documentation, this patch adds a method to `lona.Server` that shields all aiohttp request handlers from cancellation. Signed-off-by: Florian Scherf --- lona/server.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lona/server.py b/lona/server.py index 1eaa48f1..612e0749 100644 --- a/lona/server.py +++ b/lona/server.py @@ -174,7 +174,7 @@ def __init__(self, project_root: str, '*', static_url, self._handle_static_file_request) self._app.router.add_route( - '*', '/{path_info:.*}', self._handle_http_request) + '*', '/{path_info:.*}', self._shielded_handle_http_request) # setup view loader server_logger.debug('setup view loader') @@ -636,6 +636,18 @@ async def _handle_http_request(self, http_request): return self._render_response(response) + async def _shielded_handle_http_request(self, request): + """ + Runs `Server._handle_http_request` shielded from cancelation + + aiohttp 3.9 introduced web handler cancellation + (https://docs.aiohttp.org/en/v3.9.0/web_advanced.html#web-handler-cancellation) + which creates race conditions in the connections teardown code when + enabled. + """ + + return await asyncio.shield(self._handle_http_request(request)) + # public api ############################################################## @overload def run_coroutine_sync(