mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Fixed #31515 -- Made ASGIHandler dispatch lifecycle signals with thread sensitive.
This commit is contained in:
		
				
					committed by
					
						 Carlton Gibson
						Carlton Gibson
					
				
			
			
				
	
			
			
			
						parent
						
							b2ef3d7157
						
					
				
				
					commit
					92507bf3ea
				
			| @@ -151,7 +151,7 @@ class ASGIHandler(base.BaseHandler): | ||||
|             return | ||||
|         # Request is complete and can be served. | ||||
|         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. | ||||
|         request, error_response = self.create_request(scope, body_file) | ||||
|         if request is None: | ||||
| @@ -259,7 +259,7 @@ class ASGIHandler(base.BaseHandler): | ||||
|                     'body': chunk, | ||||
|                     'more_body': not last, | ||||
|                 }) | ||||
|         await sync_to_async(response.close)() | ||||
|         await sync_to_async(response.close, thread_sensitive=True)() | ||||
|  | ||||
|     @classmethod | ||||
|     def chunk_bytes(cls, data): | ||||
|   | ||||
| @@ -1,11 +1,13 @@ | ||||
| import asyncio | ||||
| import sys | ||||
| import threading | ||||
| from unittest import skipIf | ||||
|  | ||||
| from asgiref.sync import SyncToAsync | ||||
| from asgiref.testing import ApplicationCommunicator | ||||
|  | ||||
| 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.test import AsyncRequestFactory, SimpleTestCase, override_settings | ||||
|  | ||||
| @@ -151,3 +153,38 @@ class ASGITest(SimpleTestCase): | ||||
|         response_body = await communicator.receive_output() | ||||
|         self.assertEqual(response_body['type'], 'http.response.body') | ||||
|         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) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user