diff options
| author | James Thorniley <james.thorniley@mixcloud.com> | 2024-01-04 13:14:30 +0000 |
|---|---|---|
| committer | Natalia <124304+nessita@users.noreply.github.com> | 2024-01-31 14:45:44 -0300 |
| commit | f1fbd061ac34f0afdaac4a5c7db099c39b43cb4a (patch) | |
| tree | a6f0f2d66f987a99e3303f91c757afefc436e045 /django | |
| parent | bbb9ef3c62674e94ad8e6556933b112d84891f3d (diff) | |
[5.0.x] Fixed #35059 -- Ensured that ASGIHandler always sends the request_finished signal.
Prior to this work, when async tasks that process the request are cancelled due
to receiving an early "http.disconnect" ASGI message, the request_finished
signal was not being sent, potentially leading to resource leaks (such as
database connections).
This branch ensures that the request_finished signal is sent even in the case
of early termination of the response.
Regression in 64cea1e48f285ea2162c669208d95188b32bbc82.
Co-authored-by: Natalia <124304+nessita@users.noreply.github.com>
Co-authored-by: Carlton Gibson <carlton.gibson@noumenal.es>
Backport of 11393ab1316f973c5fbb534305750740d909b4e4 from main
Diffstat (limited to 'django')
| -rw-r--r-- | django/core/handlers/asgi.py | 18 |
1 files changed, 16 insertions, 2 deletions
diff --git a/django/core/handlers/asgi.py b/django/core/handlers/asgi.py index 7b0086fb76..3af080599a 100644 --- a/django/core/handlers/asgi.py +++ b/django/core/handlers/asgi.py @@ -186,11 +186,18 @@ class ASGIHandler(base.BaseHandler): if request is None: body_file.close() await self.send_response(error_response, send) + await sync_to_async(error_response.close)() return async def process_request(request, send): response = await self.run_get_response(request) - await self.send_response(response, send) + try: + await self.send_response(response, send) + except asyncio.CancelledError: + # Client disconnected during send_response (ignore exception). + pass + + return response # Try to catch a disconnect while getting response. tasks = [ @@ -221,6 +228,14 @@ class ASGIHandler(base.BaseHandler): except asyncio.CancelledError: # Task re-raised the CancelledError as expected. pass + + try: + response = tasks[1].result() + except asyncio.CancelledError: + await signals.request_finished.asend(sender=self.__class__) + else: + await sync_to_async(response.close)() + body_file.close() async def listen_for_disconnect(self, receive): @@ -346,7 +361,6 @@ class ASGIHandler(base.BaseHandler): "more_body": not last, } ) - await sync_to_async(response.close, thread_sensitive=True)() @classmethod def chunk_bytes(cls, data): |
