mirror of https://github.com/django/django.git
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.
This commit is contained in:
parent
0b4fe82c74
commit
e17ee44688
|
@ -56,9 +56,9 @@ class StaticFilesHandlerMixin:
|
||||||
|
|
||||||
async def get_response_async(self, request):
|
async def get_response_async(self, request):
|
||||||
try:
|
try:
|
||||||
return await sync_to_async(self.serve)(request)
|
return await sync_to_async(self.serve, thread_sensitive=False)(request)
|
||||||
except Http404 as e:
|
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):
|
class StaticFilesHandler(StaticFilesHandlerMixin, WSGIHandler):
|
||||||
|
|
|
@ -148,7 +148,7 @@ class BaseHandler:
|
||||||
response = await self._middleware_chain(request)
|
response = await self._middleware_chain(request)
|
||||||
response._resource_closers.append(request.close)
|
response._resource_closers.append(request.close)
|
||||||
if response.status_code >= 400:
|
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,
|
'%s: %s', response.reason_phrase, request.path,
|
||||||
response=response,
|
response=response,
|
||||||
request=request,
|
request=request,
|
||||||
|
|
|
@ -37,7 +37,7 @@ def convert_exception_to_response(get_response):
|
||||||
try:
|
try:
|
||||||
response = await get_response(request)
|
response = await get_response(request)
|
||||||
except Exception as exc:
|
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 response
|
||||||
return inner
|
return inner
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -181,7 +181,7 @@ class AsyncClientHandler(BaseHandler):
|
||||||
body_file = FakePayload('')
|
body_file = FakePayload('')
|
||||||
|
|
||||||
request_started.disconnect(close_old_connections)
|
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_started.connect(close_old_connections)
|
||||||
request = ASGIRequest(scope, body_file)
|
request = ASGIRequest(scope, body_file)
|
||||||
# Sneaky little hack so that we can easily get round
|
# Sneaky little hack so that we can easily get round
|
||||||
|
@ -197,14 +197,14 @@ class AsyncClientHandler(BaseHandler):
|
||||||
response.asgi_request = request
|
response.asgi_request = request
|
||||||
# Emulate a server by calling the close method on completion.
|
# Emulate a server by calling the close method on completion.
|
||||||
if response.streaming:
|
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.streaming_content,
|
||||||
response.close,
|
response.close,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
request_finished.disconnect(close_old_connections)
|
request_finished.disconnect(close_old_connections)
|
||||||
# Will fire request_finished.
|
# 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)
|
request_finished.connect(close_old_connections)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
|
@ -51,3 +51,5 @@ Bugfixes
|
||||||
|
|
||||||
* Fixed a regression in Django 3.1 that invalidated pre-Django 3.1 password
|
* Fixed a regression in Django 3.1 that invalidated pre-Django 3.1 password
|
||||||
reset tokens (:ticket:`32130`).
|
reset tokens (:ticket:`32130`).
|
||||||
|
|
||||||
|
* Added support for ``asgiref`` 3.3 (:ticket:`32128`).
|
||||||
|
|
|
@ -214,14 +214,14 @@ as ensuring threadlocals work, it also enables the ``thread_sensitive`` mode of
|
||||||
``sync_to_async()``
|
``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
|
Takes a sync function and returns an async function that wraps it. Can be used
|
||||||
as either a direct wrapper or a decorator::
|
as either a direct wrapper or a decorator::
|
||||||
|
|
||||||
from asgiref.sync import sync_to_async
|
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)
|
async_function = sync_to_async(sensitive_sync_function, thread_sensitive=True)
|
||||||
|
|
||||||
@sync_to_async
|
@sync_to_async
|
||||||
|
@ -234,13 +234,21 @@ directions.
|
||||||
Sync functions tend to be written assuming they all run in the main
|
Sync functions tend to be written assuming they all run in the main
|
||||||
thread, so :func:`sync_to_async` has two threading modes:
|
thread, so :func:`sync_to_async` has two threading modes:
|
||||||
|
|
||||||
* ``thread_sensitive=False`` (the default): the sync function will run in a
|
* ``thread_sensitive=True`` (the default): the sync function will run in the
|
||||||
brand new thread which is then closed once the invocation completes.
|
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
|
* ``thread_sensitive=False``: the sync function will run in a brand new thread
|
||||||
all other ``thread_sensitive`` functions. This will be the main thread, if
|
which is then closed once the invocation completes.
|
||||||
the main thread is synchronous and you are using the :func:`async_to_sync`
|
|
||||||
wrapper.
|
.. 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
|
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*
|
functions in the same thread. Note, though, that it *relies on usage of*
|
||||||
|
|
Loading…
Reference in New Issue