mirror of
https://github.com/django/django.git
synced 2025-03-06 07:22:32 +00:00
Fixed #31515 -- Made ASGIHandler dispatch lifecycle signals with thread sensitive.
This commit is contained in:
parent
b2ef3d7157
commit
92507bf3ea
@ -151,7 +151,7 @@ class ASGIHandler(base.BaseHandler):
|
|||||||
return
|
return
|
||||||
# Request is complete and can be served.
|
# Request is complete and can be served.
|
||||||
set_script_prefix(self.get_script_prefix(scope))
|
set_script_prefix(self.get_script_prefix(scope))
|
||||||
await sync_to_async(signals.request_started.send)(sender=self.__class__, scope=scope)
|
await sync_to_async(signals.request_started.send, thread_sensitive=True)(sender=self.__class__, scope=scope)
|
||||||
# Get the request and check for basic issues.
|
# Get the request and check for basic issues.
|
||||||
request, error_response = self.create_request(scope, body_file)
|
request, error_response = self.create_request(scope, body_file)
|
||||||
if request is None:
|
if request is None:
|
||||||
@ -259,7 +259,7 @@ class ASGIHandler(base.BaseHandler):
|
|||||||
'body': chunk,
|
'body': chunk,
|
||||||
'more_body': not last,
|
'more_body': not last,
|
||||||
})
|
})
|
||||||
await sync_to_async(response.close)()
|
await sync_to_async(response.close, thread_sensitive=True)()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def chunk_bytes(cls, data):
|
def chunk_bytes(cls, data):
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import sys
|
import sys
|
||||||
|
import threading
|
||||||
from unittest import skipIf
|
from unittest import skipIf
|
||||||
|
|
||||||
|
from asgiref.sync import SyncToAsync
|
||||||
from asgiref.testing import ApplicationCommunicator
|
from asgiref.testing import ApplicationCommunicator
|
||||||
|
|
||||||
from django.core.asgi import get_asgi_application
|
from django.core.asgi import get_asgi_application
|
||||||
from django.core.signals import request_started
|
from django.core.signals import request_finished, request_started
|
||||||
from django.db import close_old_connections
|
from django.db import close_old_connections
|
||||||
from django.test import AsyncRequestFactory, SimpleTestCase, override_settings
|
from django.test import AsyncRequestFactory, SimpleTestCase, override_settings
|
||||||
|
|
||||||
@ -151,3 +153,38 @@ class ASGITest(SimpleTestCase):
|
|||||||
response_body = await communicator.receive_output()
|
response_body = await communicator.receive_output()
|
||||||
self.assertEqual(response_body['type'], 'http.response.body')
|
self.assertEqual(response_body['type'], 'http.response.body')
|
||||||
self.assertEqual(response_body['body'], b'')
|
self.assertEqual(response_body['body'], b'')
|
||||||
|
|
||||||
|
async def test_request_lifecycle_signals_dispatched_with_thread_sensitive(self):
|
||||||
|
class SignalHandler:
|
||||||
|
"""Track threads handler is dispatched on."""
|
||||||
|
threads = []
|
||||||
|
|
||||||
|
def __call__(self, **kwargs):
|
||||||
|
self.threads.append(threading.current_thread())
|
||||||
|
|
||||||
|
signal_handler = SignalHandler()
|
||||||
|
request_started.connect(signal_handler)
|
||||||
|
request_finished.connect(signal_handler)
|
||||||
|
|
||||||
|
# Perform a basic request.
|
||||||
|
application = get_asgi_application()
|
||||||
|
scope = self.async_request_factory._base_scope(path='/')
|
||||||
|
communicator = ApplicationCommunicator(application, scope)
|
||||||
|
await communicator.send_input({'type': 'http.request'})
|
||||||
|
response_start = await communicator.receive_output()
|
||||||
|
self.assertEqual(response_start['type'], 'http.response.start')
|
||||||
|
self.assertEqual(response_start['status'], 200)
|
||||||
|
response_body = await communicator.receive_output()
|
||||||
|
self.assertEqual(response_body['type'], 'http.response.body')
|
||||||
|
self.assertEqual(response_body['body'], b'Hello World!')
|
||||||
|
# Give response.close() time to finish.
|
||||||
|
await communicator.wait()
|
||||||
|
|
||||||
|
# At this point, AsyncToSync does not have a current executor. Thus
|
||||||
|
# SyncToAsync falls-back to .single_thread_executor.
|
||||||
|
target_thread = next(iter(SyncToAsync.single_thread_executor._threads))
|
||||||
|
request_started_thread, request_finished_thread = signal_handler.threads
|
||||||
|
self.assertEqual(request_started_thread, target_thread)
|
||||||
|
self.assertEqual(request_finished_thread, target_thread)
|
||||||
|
request_started.disconnect(signal_handler)
|
||||||
|
request_finished.disconnect(signal_handler)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user