Skip to content

Commit

Permalink
Fix CancelledError stopping other cleanup contexts completing (#8908)
Browse files Browse the repository at this point in the history
  • Loading branch information
Dreamsorcerer authored Sep 1, 2024
1 parent 8a525d9 commit 032fb57
Show file tree
Hide file tree
Showing 4 changed files with 14 additions and 12 deletions.
1 change: 1 addition & 0 deletions CHANGES/8908.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed ``CancelledError`` from one cleanup context stopping other contexts from completing -- by :user:`Dreamsorcerer`.
2 changes: 1 addition & 1 deletion aiohttp/web_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ async def _on_cleanup(self, app: Application) -> None:
await it.__anext__()
except StopAsyncIteration:
pass
except Exception as exc:
except (Exception, asyncio.CancelledError) as exc:
errors.append(exc)
else:
errors.append(RuntimeError(f"{it!r} has more than one 'yield'"))
Expand Down
14 changes: 6 additions & 8 deletions docs/web_advanced.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1068,13 +1068,10 @@ below::
async with client.pubsub() as pubsub:
await pubsub.subscribe(channel)
while True:
try:
msg = await pubsub.get_message(ignore_subscribe_messages=True)
if msg is not None:
for ws in app["websockets"]:
await ws.send_str("{}: {}".format(channel, msg))
except asyncio.CancelledError:
break
msg = await pubsub.get_message(ignore_subscribe_messages=True)
if msg is not None:
for ws in app["websockets"]:
await ws.send_str("{}: {}".format(channel, msg))


async def background_tasks(app):
Expand All @@ -1083,7 +1080,8 @@ below::
yield

app[redis_listener].cancel()
await app[redis_listener]
with contextlib.suppress(asyncio.CancelledError):
await app[redis_listener]


app = web.Application()
Expand Down
9 changes: 6 additions & 3 deletions tests/test_web_app.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import asyncio
from typing import Any, AsyncIterator, Callable, Iterator, NoReturn
from typing import Any, AsyncIterator, Callable, Iterator, NoReturn, Type
from unittest import mock

import pytest
Expand Down Expand Up @@ -334,7 +334,10 @@ async def fail_ctx(app: web.Application) -> AsyncIterator[NoReturn]:
assert ctx_state == "CLEAN"


async def test_cleanup_ctx_exception_on_cleanup_multiple() -> None:
@pytest.mark.parametrize("exc_cls", (Exception, asyncio.CancelledError))
async def test_cleanup_ctx_exception_on_cleanup_multiple(
exc_cls: Type[BaseException],
) -> None:
app = web.Application()
out = []

Expand All @@ -346,7 +349,7 @@ async def inner(app: web.Application) -> AsyncIterator[None]:
yield None
out.append("post_" + str(num))
if fail:
raise Exception("fail_" + str(num))
raise exc_cls("fail_" + str(num))

return inner

Expand Down

0 comments on commit 032fb57

Please sign in to comment.