async.txt 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. ====================
  2. Asynchronous support
  3. ====================
  4. .. currentmodule:: asgiref.sync
  5. Django has support for writing asynchronous ("async") views, along with an
  6. entirely async-enabled request stack if you are running under
  7. :doc:`ASGI </howto/deployment/asgi/index>`. Async views will still work under
  8. WSGI, but with performance penalties, and without the ability to have efficient
  9. long-running requests.
  10. We're still working on async support for the ORM and other parts of Django.
  11. You can expect to see this in future releases. For now, you can use the
  12. :func:`sync_to_async` adapter to interact with the sync parts of Django.
  13. There is also a whole range of async-native Python libraries that you can
  14. integrate with.
  15. Async views
  16. ===========
  17. Any view can be declared async by making the callable part of it return a
  18. coroutine - commonly, this is done using ``async def``. For a function-based
  19. view, this means declaring the whole view using ``async def``. For a
  20. class-based view, this means declaring the HTTP method handlers, such as
  21. ``get()`` and ``post()`` as ``async def`` (not its ``__init__()``, or
  22. ``as_view()``).
  23. .. note::
  24. Django uses ``asgiref.sync.iscoroutinefunction`` to test if your view is
  25. asynchronous or not. If you implement your own method of returning a
  26. coroutine, ensure you use ``asgiref.sync.markcoroutinefunction`` so this
  27. function returns ``True``.
  28. Under a WSGI server, async views will run in their own, one-off event loop.
  29. This means you can use async features, like concurrent async HTTP requests,
  30. without any issues, but you will not get the benefits of an async stack.
  31. The main benefits are the ability to service hundreds of connections without
  32. using Python threads. This allows you to use slow streaming, long-polling, and
  33. other exciting response types.
  34. If you want to use these, you will need to deploy Django using
  35. :doc:`ASGI </howto/deployment/asgi/index>` instead.
  36. .. warning::
  37. You will only get the benefits of a fully-asynchronous request stack if you
  38. have *no synchronous middleware* loaded into your site. If there is a piece
  39. of synchronous middleware, then Django must use a thread per request to
  40. safely emulate a synchronous environment for it.
  41. Middleware can be built to support :ref:`both sync and async
  42. <async-middleware>` contexts. Some of Django's middleware is built like
  43. this, but not all. To see what middleware Django has to adapt for, you can
  44. turn on debug logging for the ``django.request`` logger and look for log
  45. messages about *"Asynchronous handler adapted for middleware ..."*.
  46. In both ASGI and WSGI mode, you can still safely use asynchronous support to
  47. run code concurrently rather than serially. This is especially handy when
  48. dealing with external APIs or data stores.
  49. If you want to call a part of Django that is still synchronous, you will need
  50. to wrap it in a :func:`sync_to_async` call. For example::
  51. from asgiref.sync import sync_to_async
  52. results = await sync_to_async(sync_function, thread_sensitive=True)(pk=123)
  53. If you accidentally try to call a part of Django that is synchronous-only
  54. from an async view, you will trigger Django's
  55. :ref:`asynchronous safety protection <async-safety>` to protect your data from
  56. corruption.
  57. Decorators
  58. ----------
  59. .. versionadded:: 5.0
  60. The following decorators can be used with both synchronous and asynchronous
  61. view functions:
  62. * :func:`~django.views.decorators.cache.cache_control`
  63. * :func:`~django.views.decorators.cache.never_cache`
  64. * :func:`~django.views.decorators.common.no_append_slash`
  65. * :func:`~django.views.decorators.csrf.csrf_exempt`
  66. * :func:`~django.views.decorators.csrf.csrf_protect`
  67. * :func:`~django.views.decorators.csrf.ensure_csrf_cookie`
  68. * :func:`~django.views.decorators.csrf.requires_csrf_token`
  69. * :func:`~django.views.decorators.debug.sensitive_variables`
  70. * :func:`~django.views.decorators.debug.sensitive_post_parameters`
  71. * :func:`~django.views.decorators.gzip.gzip_page`
  72. * :func:`~django.views.decorators.http.condition`
  73. * ``conditional_page()``
  74. * :func:`~django.views.decorators.http.etag`
  75. * :func:`~django.views.decorators.http.last_modified`
  76. * :func:`~django.views.decorators.http.require_http_methods`
  77. * :func:`~django.views.decorators.http.require_GET`
  78. * :func:`~django.views.decorators.http.require_POST`
  79. * :func:`~django.views.decorators.http.require_safe`
  80. * :func:`~django.views.decorators.vary.vary_on_cookie`
  81. * :func:`~django.views.decorators.vary.vary_on_headers`
  82. * ``xframe_options_deny()``
  83. * ``xframe_options_sameorigin()``
  84. * ``xframe_options_exempt()``
  85. For example::
  86. from django.views.decorators.cache import never_cache
  87. @never_cache
  88. def my_sync_view(request):
  89. ...
  90. @never_cache
  91. async def my_async_view(request):
  92. ...
  93. Queries & the ORM
  94. -----------------
  95. With some exceptions, Django can run ORM queries asynchronously as well::
  96. async for author in Author.objects.filter(name__startswith="A"):
  97. book = await author.books.afirst()
  98. Detailed notes can be found in :ref:`async-queries`, but in short:
  99. * All ``QuerySet`` methods that cause an SQL query to occur have an
  100. ``a``-prefixed asynchronous variant.
  101. * ``async for`` is supported on all QuerySets (including the output of
  102. ``values()`` and ``values_list()``.)
  103. Django also supports some asynchronous model methods that use the database::
  104. async def make_book(*args, **kwargs):
  105. book = Book(...)
  106. await book.asave(using="secondary")
  107. async def make_book_with_tags(tags, *args, **kwargs):
  108. book = await Book.objects.acreate(...)
  109. await book.tags.aset(tags)
  110. Transactions do not yet work in async mode. If you have a piece of code that
  111. needs transactions behavior, we recommend you write that piece as a single
  112. synchronous function and call it using :func:`sync_to_async`.
  113. .. versionchanged:: 4.2
  114. Asynchronous model and related manager interfaces were added.
  115. .. _async_performance:
  116. Performance
  117. -----------
  118. When running in a mode that does not match the view (e.g. an async view under
  119. WSGI, or a traditional sync view under ASGI), Django must emulate the other
  120. call style to allow your code to run. This context-switch causes a small
  121. performance penalty of around a millisecond.
  122. This is also true of middleware. Django will attempt to minimize the number of
  123. context-switches between sync and async. If you have an ASGI server, but all
  124. your middleware and views are synchronous, it will switch just once, before it
  125. enters the middleware stack.
  126. However, if you put synchronous middleware between an ASGI server and an
  127. asynchronous view, it will have to switch into sync mode for the middleware and
  128. then back to async mode for the view. Django will also hold the sync thread
  129. open for middleware exception propagation. This may not be noticeable at first,
  130. but adding this penalty of one thread per request can remove any async
  131. performance advantage.
  132. You should do your own performance testing to see what effect ASGI versus WSGI
  133. has on your code. In some cases, there may be a performance increase even for
  134. a purely synchronous codebase under ASGI because the request-handling code is
  135. still all running asynchronously. In general you will only want to enable ASGI
  136. mode if you have asynchronous code in your project.
  137. .. _async-handling-disconnect:
  138. Handling disconnects
  139. --------------------
  140. .. versionadded:: 5.0
  141. For long-lived requests, a client may disconnect before the view returns a
  142. response. In this case, an ``asyncio.CancelledError`` will be raised in the
  143. view. You can catch this error and handle it if you need to perform any
  144. cleanup::
  145. async def my_view(request):
  146. try:
  147. # Do some work
  148. ...
  149. except asyncio.CancelledError:
  150. # Handle disconnect
  151. raise
  152. You can also :ref:`handle client disconnects in streaming responses
  153. <request-response-streaming-disconnect>`.
  154. .. _async-safety:
  155. Async safety
  156. ============
  157. .. envvar:: DJANGO_ALLOW_ASYNC_UNSAFE
  158. Certain key parts of Django are not able to operate safely in an async
  159. environment, as they have global state that is not coroutine-aware. These parts
  160. of Django are classified as "async-unsafe", and are protected from execution in
  161. an async environment. The ORM is the main example, but there are other parts
  162. that are also protected in this way.
  163. If you try to run any of these parts from a thread where there is a *running
  164. event loop*, you will get a
  165. :exc:`~django.core.exceptions.SynchronousOnlyOperation` error. Note that you
  166. don't have to be inside an async function directly to have this error occur. If
  167. you have called a sync function directly from an async function,
  168. without using :func:`sync_to_async` or similar, then it can also occur. This is
  169. because your code is still running in a thread with an active event loop, even
  170. though it may not be declared as async code.
  171. If you encounter this error, you should fix your code to not call the offending
  172. code from an async context. Instead, write your code that talks to async-unsafe
  173. functions in its own, sync function, and call that using
  174. :func:`asgiref.sync.sync_to_async` (or any other way of running sync code in
  175. its own thread).
  176. The async context can be imposed upon you by the environment in which you are
  177. running your Django code. For example, Jupyter_ notebooks and IPython_
  178. interactive shells both transparently provide an active event loop so that it is
  179. easier to interact with asynchronous APIs.
  180. If you're using an IPython shell, you can disable this event loop by running:
  181. .. code-block:: shell
  182. %autoawait off
  183. as a command at the IPython prompt. This will allow you to run synchronous code
  184. without generating :exc:`~django.core.exceptions.SynchronousOnlyOperation`
  185. errors; however, you also won't be able to ``await`` asynchronous APIs. To turn
  186. the event loop back on, run:
  187. .. code-block:: shell
  188. %autoawait on
  189. If you're in an environment other than IPython (or you can't turn off
  190. ``autoawait`` in IPython for some reason), you are *certain* there is no chance
  191. of your code being run concurrently, and you *absolutely* need to run your sync
  192. code from an async context, then you can disable the warning by setting the
  193. :envvar:`DJANGO_ALLOW_ASYNC_UNSAFE` environment variable to any value.
  194. .. warning::
  195. If you enable this option and there is concurrent access to the
  196. async-unsafe parts of Django, you may suffer data loss or corruption. Be
  197. very careful and do not use this in production environments.
  198. If you need to do this from within Python, do that with ``os.environ``::
  199. import os
  200. os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = "true"
  201. .. _Jupyter: https://jupyter.org/
  202. .. _IPython: https://ipython.org
  203. Async adapter functions
  204. =======================
  205. It is necessary to adapt the calling style when calling sync code from an async
  206. context, or vice-versa. For this there are two adapter functions, from the
  207. ``asgiref.sync`` module: :func:`async_to_sync` and :func:`sync_to_async`. They
  208. are used to transition between the calling styles while preserving
  209. compatibility.
  210. These adapter functions are widely used in Django. The :pypi:`asgiref` package
  211. itself is part of the Django project, and it is automatically installed as a
  212. dependency when you install Django with ``pip``.
  213. ``async_to_sync()``
  214. -------------------
  215. .. function:: async_to_sync(async_function, force_new_loop=False)
  216. Takes an async function and returns a sync function that wraps it. Can be used
  217. as either a direct wrapper or a decorator::
  218. from asgiref.sync import async_to_sync
  219. async def get_data():
  220. ...
  221. sync_get_data = async_to_sync(get_data)
  222. @async_to_sync
  223. async def get_other_data():
  224. ...
  225. The async function is run in the event loop for the current thread, if one is
  226. present. If there is no current event loop, a new event loop is spun up
  227. specifically for the single async invocation and shut down again once it
  228. completes. In either situation, the async function will execute on a different
  229. thread to the calling code.
  230. Threadlocals and contextvars values are preserved across the boundary in both
  231. directions.
  232. :func:`async_to_sync` is essentially a more powerful version of the
  233. :py:func:`asyncio.run` function in Python's standard library. As well
  234. as ensuring threadlocals work, it also enables the ``thread_sensitive`` mode of
  235. :func:`sync_to_async` when that wrapper is used below it.
  236. ``sync_to_async()``
  237. -------------------
  238. .. function:: sync_to_async(sync_function, thread_sensitive=True)
  239. Takes a sync function and returns an async function that wraps it. Can be used
  240. as either a direct wrapper or a decorator::
  241. from asgiref.sync import sync_to_async
  242. async_function = sync_to_async(sync_function, thread_sensitive=False)
  243. async_function = sync_to_async(sensitive_sync_function, thread_sensitive=True)
  244. @sync_to_async
  245. def sync_function():
  246. ...
  247. Threadlocals and contextvars values are preserved across the boundary in both
  248. directions.
  249. Sync functions tend to be written assuming they all run in the main
  250. thread, so :func:`sync_to_async` has two threading modes:
  251. * ``thread_sensitive=True`` (the default): the sync function will run in the
  252. same thread as all other ``thread_sensitive`` functions. This will be the
  253. main thread, if the main thread is synchronous and you are using the
  254. :func:`async_to_sync` wrapper.
  255. * ``thread_sensitive=False``: the sync function will run in a brand new thread
  256. which is then closed once the invocation completes.
  257. .. warning::
  258. ``asgiref`` version 3.3.0 changed the default value of the
  259. ``thread_sensitive`` parameter to ``True``. This is a safer default, and in
  260. many cases interacting with Django the correct value, but be sure to
  261. evaluate uses of ``sync_to_async()`` if updating ``asgiref`` from a prior
  262. version.
  263. Thread-sensitive mode is quite special, and does a lot of work to run all
  264. functions in the same thread. Note, though, that it *relies on usage of*
  265. :func:`async_to_sync` *above it in the stack* to correctly run things on the
  266. main thread. If you use ``asyncio.run()`` or similar, it will fall back to
  267. running thread-sensitive functions in a single, shared thread, but this will
  268. not be the main thread.
  269. The reason this is needed in Django is that many libraries, specifically
  270. database adapters, require that they are accessed in the same thread that they
  271. were created in. Also a lot of existing Django code assumes it all runs in the
  272. same thread, e.g. middleware adding things to a request for later use in views.
  273. Rather than introduce potential compatibility issues with this code, we instead
  274. opted to add this mode so that all existing Django sync code runs in the same
  275. thread and thus is fully compatible with async mode. Note that sync code will
  276. always be in a *different* thread to any async code that is calling it, so you
  277. should avoid passing raw database handles or other thread-sensitive references
  278. around.
  279. In practice this restriction means that you should not pass features of the
  280. database ``connection`` object when calling ``sync_to_async()``. Doing so will
  281. trigger the thread safety checks:
  282. .. code-block:: pycon
  283. # DJANGO_SETTINGS_MODULE=settings.py python -m asyncio
  284. >>> import asyncio
  285. >>> from asgiref.sync import sync_to_async
  286. >>> from django.db import connection
  287. >>> # In an async context so you cannot use the database directly:
  288. >>> connection.cursor()
  289. django.core.exceptions.SynchronousOnlyOperation: You cannot call this from
  290. an async context - use a thread or sync_to_async.
  291. >>> # Nor can you pass resolved connection attributes across threads:
  292. >>> await sync_to_async(connection.cursor)()
  293. django.db.utils.DatabaseError: DatabaseWrapper objects created in a thread
  294. can only be used in that same thread. The object with alias 'default' was
  295. created in thread id 4371465600 and this is thread id 6131478528.
  296. Rather, you should encapsulate all database access within a helper function
  297. that can be called with ``sync_to_async()`` without relying on the connection
  298. object in the calling code.
  299. Use with exception reporting filters
  300. ------------------------------------
  301. .. warning::
  302. Due to the machinery needed to cross the sync/async boundary,
  303. ``sync_to_async()`` and ``async_to_sync()`` are **not** compatible with
  304. :func:`~django.views.decorators.debug.sensitive_variables`, used to mask
  305. local variables from exception reports.
  306. If using these adapters with sensitive variables, ensure to audit exception
  307. reporting, and consider implementing a :ref:`custom filter
  308. <custom-error-reports>` if necessary.