From 378a5745ede5144c58c6bdd2821f72f63c7e58f2 Mon Sep 17 00:00:00 2001 From: Sam Bull Date: Mon, 5 Aug 2024 17:24:35 +0100 Subject: [PATCH 1/3] Fix handler waiting on shutdown --- aiohttp/web_protocol.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/aiohttp/web_protocol.py b/aiohttp/web_protocol.py index 1b4e7e66cd8..7b8a2a72d68 100644 --- a/aiohttp/web_protocol.py +++ b/aiohttp/web_protocol.py @@ -163,6 +163,7 @@ class RequestHandler(BaseProtocol): "_lingering_time", "_messages", "_message_tail", + "_handler_waiter", "_waiter", "_task_handler", "_upgrade", @@ -215,6 +216,7 @@ def __init__( self._message_tail = b"" self._waiter: Optional[asyncio.Future[None]] = None + self._handler_waiter: Optional[asyncio.Future[None]] = None self._task_handler: Optional[asyncio.Task[None]] = None self._upgrade = False @@ -278,11 +280,9 @@ async def shutdown(self, timeout: Optional[float] = 15.0) -> None: if self._waiter: self._waiter.cancel() - # Wait for graceful disconnection - if self._current_request is not None: - with suppress(asyncio.CancelledError, asyncio.TimeoutError): - async with ceil_timeout(timeout): - await self._current_request.wait_for_disconnection() + # Wait for graceful handler completion + if self._handler_waiter is not None: + await self._handler_waiter # Then cancel handler and wait with suppress(asyncio.CancelledError, asyncio.TimeoutError): async with ceil_timeout(timeout): @@ -466,6 +466,7 @@ async def _handle_request( start_time: float, request_handler: Callable[[BaseRequest], Awaitable[StreamResponse]], ) -> Tuple[StreamResponse, bool]: + self._handler_waiter = self._loop.create_future() try: try: self._current_request = request @@ -489,6 +490,8 @@ async def _handle_request( reset = await self.finish_response(request, resp, start_time) else: reset = await self.finish_response(request, resp, start_time) + finally: + self._handler_waiter.set_result(None) return resp, reset From e34a1c1cc34c0322d9cd66337b33850438c0aae7 Mon Sep 17 00:00:00 2001 From: Sam Bull Date: Mon, 5 Aug 2024 17:33:44 +0100 Subject: [PATCH 2/3] Create 8611.bugfix.rst --- CHANGES/8611.bugfix.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 CHANGES/8611.bugfix.rst diff --git a/CHANGES/8611.bugfix.rst b/CHANGES/8611.bugfix.rst new file mode 100644 index 00000000000..2cd795cc14e --- /dev/null +++ b/CHANGES/8611.bugfix.rst @@ -0,0 +1 @@ +Fixed an edge case where shutdown would wait for timeout when handler was already completed -- by :user:`Dreamsorcerer`. From 99b0c5a4357160691634b8734018058005949819 Mon Sep 17 00:00:00 2001 From: Sam Bull Date: Mon, 5 Aug 2024 20:11:44 +0100 Subject: [PATCH 3/3] Update web_protocol.py --- aiohttp/web_protocol.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/aiohttp/web_protocol.py b/aiohttp/web_protocol.py index 7b8a2a72d68..4d50465b2ef 100644 --- a/aiohttp/web_protocol.py +++ b/aiohttp/web_protocol.py @@ -282,7 +282,9 @@ async def shutdown(self, timeout: Optional[float] = 15.0) -> None: # Wait for graceful handler completion if self._handler_waiter is not None: - await self._handler_waiter + with suppress(asyncio.CancelledError, asyncio.TimeoutError): + async with ceil_timeout(timeout): + await self._handler_waiter # Then cancel handler and wait with suppress(asyncio.CancelledError, asyncio.TimeoutError): async with ceil_timeout(timeout):