diff options
| author | Thomas Grainger <tagrain@gmail.com> | 2025-11-07 11:14:06 -0500 |
|---|---|---|
| committer | Jacob Walls <jacobtylerwalls@gmail.com> | 2025-11-07 12:23:31 -0500 |
| commit | 2501958b5127020411df6271445ccfd0906df70e (patch) | |
| tree | 8b4acb38b1f3372e9e79328f84efa0f2eca5f63a /django/core | |
| parent | 796cf3d325b4a1b9d9b5361c2c8c28a5edcfe89b (diff) | |
Refs #36315 -- Replaced manual task and cancellation handling with TaskGroup in ASGIHandler.
Diffstat (limited to 'django/core')
| -rw-r--r-- | django/core/handlers/asgi.py | 56 |
1 files changed, 16 insertions, 40 deletions
diff --git a/django/core/handlers/asgi.py b/django/core/handlers/asgi.py index dae545f3b3..af8582d539 100644 --- a/django/core/handlers/asgi.py +++ b/django/core/handlers/asgi.py @@ -187,49 +187,25 @@ class ASGIHandler(base.BaseHandler): await sync_to_async(error_response.close)() return - async def process_request(request, send): - response = await self.run_get_response(request) + class RequestProcessed(Exception): + pass + + response = None + try: try: - await self.send_response(response, send) - except asyncio.CancelledError: - # Client disconnected during send_response (ignore exception). + async with asyncio.TaskGroup() as tg: + tg.create_task(self.listen_for_disconnect(receive)) + response = await self.run_get_response(request) + await self.send_response(response, send) + raise RequestProcessed + except* (RequestProcessed, RequestAborted): pass + except BaseExceptionGroup as exception_group: + if len(exception_group.exceptions) == 1: + raise exception_group.exceptions[0] + raise - return response - - # Try to catch a disconnect while getting response. - tasks = [ - # Check the status of these tasks and (optionally) terminate them - # in this order. The listen_for_disconnect() task goes first - # because it should not raise unexpected errors that would prevent - # us from cancelling process_request(). - asyncio.create_task(self.listen_for_disconnect(receive)), - asyncio.create_task(process_request(request, send)), - ] - await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED) - # Now wait on both tasks (they may have both finished by now). - for task in tasks: - if task.done(): - try: - task.result() - except RequestAborted: - # Ignore client disconnects. - pass - except AssertionError: - body_file.close() - raise - else: - # Allow views to handle cancellation. - task.cancel() - try: - await task - except asyncio.CancelledError: - # Task re-raised the CancelledError as expected. - pass - - try: - response = tasks[1].result() - except asyncio.CancelledError: + if response is None: await signals.request_finished.asend(sender=self.__class__) else: await sync_to_async(response.close)() |
