瀏覽代碼

Fixed #32128 -- Added asgiref 3.3 compatibility.

Thread sensitive parameter is True by default from asgiref v3.3.0.
Added an explicit thread_sensitive=False to previously implicit uses.
Carlton Gibson 4 年之前
父節點
當前提交
e17ee44688

+ 2 - 2
django/contrib/staticfiles/handlers.py

@@ -56,9 +56,9 @@ class StaticFilesHandlerMixin:
 
     async def get_response_async(self, request):
         try:
-            return await sync_to_async(self.serve)(request)
+            return await sync_to_async(self.serve, thread_sensitive=False)(request)
         except Http404 as e:
-            return await sync_to_async(response_for_exception)(request, e)
+            return await sync_to_async(response_for_exception, thread_sensitive=False)(request, e)
 
 
 class StaticFilesHandler(StaticFilesHandlerMixin, WSGIHandler):

+ 1 - 1
django/core/handlers/base.py

@@ -148,7 +148,7 @@ class BaseHandler:
         response = await self._middleware_chain(request)
         response._resource_closers.append(request.close)
         if response.status_code >= 400:
-            await sync_to_async(log_response)(
+            await sync_to_async(log_response, thread_sensitive=False)(
                 '%s: %s', response.reason_phrase, request.path,
                 response=response,
                 request=request,

+ 1 - 1
django/core/handlers/exception.py

@@ -37,7 +37,7 @@ def convert_exception_to_response(get_response):
             try:
                 response = await get_response(request)
             except Exception as exc:
-                response = await sync_to_async(response_for_exception)(request, exc)
+                response = await sync_to_async(response_for_exception, thread_sensitive=False)(request, exc)
             return response
         return inner
     else:

+ 3 - 3
django/test/client.py

@@ -181,7 +181,7 @@ class AsyncClientHandler(BaseHandler):
             body_file = FakePayload('')
 
         request_started.disconnect(close_old_connections)
-        await sync_to_async(request_started.send)(sender=self.__class__, scope=scope)
+        await sync_to_async(request_started.send, thread_sensitive=False)(sender=self.__class__, scope=scope)
         request_started.connect(close_old_connections)
         request = ASGIRequest(scope, body_file)
         # Sneaky little hack so that we can easily get round
@@ -197,14 +197,14 @@ class AsyncClientHandler(BaseHandler):
         response.asgi_request = request
         # Emulate a server by calling the close method on completion.
         if response.streaming:
-            response.streaming_content = await sync_to_async(closing_iterator_wrapper)(
+            response.streaming_content = await sync_to_async(closing_iterator_wrapper, thread_sensitive=False)(
                 response.streaming_content,
                 response.close,
             )
         else:
             request_finished.disconnect(close_old_connections)
             # Will fire request_finished.
-            await sync_to_async(response.close)()
+            await sync_to_async(response.close, thread_sensitive=False)()
             request_finished.connect(close_old_connections)
         return response
 

+ 2 - 0
docs/releases/3.1.3.txt

@@ -51,3 +51,5 @@ Bugfixes
 
 * Fixed a regression in Django 3.1 that invalidated pre-Django 3.1 password
   reset tokens (:ticket:`32130`).
+
+* Added support for ``asgiref`` 3.3 (:ticket:`32128`).

+ 16 - 8
docs/topics/async.txt

@@ -214,14 +214,14 @@ as ensuring threadlocals work, it also enables the ``thread_sensitive`` mode of
 ``sync_to_async()``
 -------------------
 
-.. function:: sync_to_async(sync_function, thread_sensitive=False)
+.. function:: sync_to_async(sync_function, thread_sensitive=True)
 
 Takes a sync function and returns an async function that wraps it. Can be used
 as either a direct wrapper or a decorator::
 
     from asgiref.sync import sync_to_async
 
-    async_function = sync_to_async(sync_function)
+    async_function = sync_to_async(sync_function, thread_sensitive=False)
     async_function = sync_to_async(sensitive_sync_function, thread_sensitive=True)
 
     @sync_to_async
@@ -234,13 +234,21 @@ directions.
 Sync functions tend to be written assuming they all run in the main
 thread, so :func:`sync_to_async` has two threading modes:
 
-* ``thread_sensitive=False`` (the default): the sync function will run in a
-  brand new thread which is then closed once the invocation completes.
+* ``thread_sensitive=True`` (the default): the sync function will run in the
+  same thread as all other ``thread_sensitive`` functions. This will be the
+  main thread, if the main thread is synchronous and you are using the
+  :func:`async_to_sync` wrapper.
 
-* ``thread_sensitive=True``: the sync function will run in the same thread as
-  all other ``thread_sensitive`` functions. This will be the main thread, if
-  the main thread is synchronous and you are using the :func:`async_to_sync`
-  wrapper.
+* ``thread_sensitive=False``: the sync function will run in a brand new thread
+  which is then closed once the invocation completes.
+
+.. warning::
+
+    ``asgiref`` version 3.3.0 changed the default value of the
+    ``thread_sensitive`` parameter to ``True``. This is a safer default, and in
+    many cases interacting with Django the correct value, but be sure to
+    evaluate uses of ``sync_to_async()`` if updating ``asgiref`` from a prior
+    version.
 
 Thread-sensitive mode is quite special, and does a lot of work to run all
 functions in the same thread. Note, though, that it *relies on usage of*