1
0
mirror of https://github.com/django/django.git synced 2025-11-07 07:15:35 +00:00

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 64cea1e48f.

Co-authored-by: Natalia <124304+nessita@users.noreply.github.com>
Co-authored-by: Carlton Gibson <carlton.gibson@noumenal.es>
This commit is contained in:
James Thorniley
2024-01-04 13:14:30 +00:00
committed by Natalia
parent a43d75e81d
commit 11393ab131
3 changed files with 153 additions and 3 deletions

View File

@@ -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):