====================
Asynchronous support
====================

.. currentmodule:: asgiref.sync

Django has support for writing asynchronous ("async") views, along with an
entirely async-enabled request stack if you are running under :doc:`ASGI
</howto/deployment/asgi/index>`. Async views will still work under WSGI, but
with a small per-request adaptation cost (see :ref:`async_performance`), and
without the ability to have efficient long-running requests.

Many parts of Django provide asynchronous APIs, including :ref:`the ORM
<async-queries>`, the cache framework, authentication, sessions, and signals.
For other code, the :func:`sync_to_async` adapter is a low-cost bridge (see
:ref:`async_performance`). A wide range of async-native Python libraries can
also be integrated.

Async views
===========

Any view can be declared async by making the callable part of it return a
coroutine - commonly, this is done using ``async def``. For a function-based
view, this means declaring the whole view using ``async def``. For a
class-based view, this means declaring the HTTP method handlers, such as
``get()`` and ``post()`` as ``async def`` (not its ``__init__()``, or
``as_view()``).

.. note::

    Django uses ``inspect.iscoroutinefunction`` to test if your view is
    asynchronous or not. If you implement your own method of returning a
    coroutine, ensure you use ``inspect.markcoroutinefunction`` so this
    function returns ``True``.

Under a WSGI server, async views will run in their own, one-off event loop.
This means you can use async features, like concurrent async HTTP requests,
without any issues, but you will not get the benefits of an async stack.

The main benefits are the ability to service hundreds of connections without
using Python threads. This allows you to use slow streaming, long-polling, and
other exciting response types.

If you want to use these, you will need to deploy Django using
:doc:`ASGI </howto/deployment/asgi/index>` instead.

.. note::

    A fully asynchronous request stack requires async middleware end-to-end.
    Where a piece of synchronous middleware sits between an ASGI server and an
    async view, Django adapts it by running it in its own thread; see
    :ref:`async_performance` for the cost trade-off.

    Django's bundled middleware supports both :ref:`sync and async
    <async-middleware>`. Third-party middleware may not. To see which
    middleware Django adapts, turn on debug logging for the ``django.request``
    logger and look for log messages about *"Asynchronous handler adapted for
    middleware ..."*.

In both ASGI and WSGI mode, you can still safely use asynchronous support to
run code concurrently rather than serially. This is especially handy when
dealing with external APIs or data stores.

If you want to call a part of Django that is still synchronous, you will need
to wrap it in a :func:`sync_to_async` call. For example::

    from asgiref.sync import sync_to_async

    results = await sync_to_async(sync_function, thread_sensitive=True)(pk=123)

If you accidentally try to call a part of Django that is synchronous-only
from an async view, you will trigger Django's
:ref:`asynchronous safety protection <async-safety>` to protect your data from
corruption.

Decorators
----------

The following decorators can be used with both synchronous and asynchronous
view functions:

* :func:`~django.views.decorators.cache.cache_control`
* :func:`~django.views.decorators.cache.never_cache`
* :func:`~django.views.decorators.common.no_append_slash`
* :func:`~django.views.decorators.csp.csp_override`
* :func:`~django.views.decorators.csp.csp_report_only_override`
* :func:`~django.views.decorators.csrf.csrf_exempt`
* :func:`~django.views.decorators.csrf.csrf_protect`
* :func:`~django.views.decorators.csrf.ensure_csrf_cookie`
* :func:`~django.views.decorators.csrf.requires_csrf_token`
* :func:`~django.views.decorators.debug.sensitive_variables`
* :func:`~django.views.decorators.debug.sensitive_post_parameters`
* :func:`~django.views.decorators.gzip.gzip_page`
* :func:`~django.views.decorators.http.condition`
* ``conditional_page()``
* :func:`~django.views.decorators.http.etag`
* :func:`~django.views.decorators.http.last_modified`
* :func:`~django.views.decorators.http.require_http_methods`
* :func:`~django.views.decorators.http.require_GET`
* :func:`~django.views.decorators.http.require_POST`
* :func:`~django.views.decorators.http.require_safe`
* :func:`~django.views.decorators.vary.vary_on_cookie`
* :func:`~django.views.decorators.vary.vary_on_headers`
* ``xframe_options_deny()``
* ``xframe_options_sameorigin()``
* ``xframe_options_exempt()``

For example::

    from django.views.decorators.cache import never_cache


    @never_cache
    def my_sync_view(request): ...


    @never_cache
    async def my_async_view(request): ...

:func:`~django.utils.decorators.method_decorator` can be used with asynchronous
methods, including ``async def`` view handlers. Note, though, that if
decorating :meth:`~django.views.generic.base.View.dispatch` on a ``View`` with
asynchronous handlers, you will need to override ``dispatch`` to make it
``async def`` as well::

    class MyClass(View):
        @method_decorator(never_cache)
        async def dispatch(self, *args, **kwargs):
            return super().dispatch(*args, **kwargs)

        async def get(self, request): ...

        async def post(self, request): ...

Here, because we are decorating ``dispatch``, rather than the individual
handler methods, we need to make ``dispatch`` asynchronous so that
``method_decorator`` can correctly mark the resulting method as a coroutine
function.

Queries & the ORM
-----------------

With some exceptions, Django can run ORM queries asynchronously::

    async for author in Author.objects.filter(name__startswith="A"):
        book = await author.books.afirst()

Detailed notes can be found in :ref:`async-queries`, but in short:

* All ``QuerySet`` methods that cause an SQL query to occur have an
  ``a``-prefixed asynchronous variant.

* ``async for`` is supported on all QuerySets (including the output of
  ``values()`` and ``values_list()``.)

Asynchronous model methods that use the database are also supported::

    async def make_book(*args, **kwargs):
        book = Book(...)
        await book.asave(using="secondary")


    async def make_book_with_tags(tags, *args, **kwargs):
        book = await Book.objects.acreate(...)
        await book.tags.aset(tags)

Transactions do not yet work in async mode. If you have a piece of code that
needs transactions behavior, we recommend you write that piece as a single
synchronous function and call it using :func:`sync_to_async`.

:ref:`Persistent database connections <persistent-database-connections>`, set
via the :setting:`CONN_MAX_AGE` setting, should also be disabled in async mode.
Instead, use your database backend's built-in connection pooling if available,
or investigate a third-party connection pooling option if required. As in
synchronous Django, concurrent requests in a single process share that pool, so
size it to the target in-flight query concurrency.

.. _async_performance:

Performance
-----------

When running in a mode that does not match the view (e.g. an async view under
WSGI, or a traditional sync view under ASGI), Django must emulate the other
call style to allow your code to run. The per-call cost of this adaptation is
small: tens of microseconds in the in-request ASGI path, where the running
event loop is reused, and a few hundred microseconds in the cold-start path
used by management commands, background tasks, and scripts. Against typical
request times measured in milliseconds, this is rarely visible in itself, but
can become so under GIL contention as the number of active threads grows.

If you find yourself wrapping individual rows or operations in a tight loop,
restructure your code so the loop runs inside a single :func:`sync_to_async`
(or :func:`async_to_sync`) crossing. The per-call cost of the context switch is
then spread across the whole loop and effectively disappears.

The same per-call adaptation cost applies to middleware. Django will attempt to
minimize the number of context-switches between sync and async. If you have an
ASGI server, but all your middleware and views are synchronous, it will switch
just once, before it enters the middleware stack.

However, if you put synchronous middleware between an ASGI server and an
asynchronous view, it will have to switch into sync mode for the middleware and
then back to async mode for the view. Django will also hold the sync thread
open for middleware exception propagation. For request/response views that hit
the ORM and return, this is not usually a meaningful penalty. It matters most
when you are using ASGI for high in-process concurrency over non-ORM I/O (for
example upstream HTTP fan-out, server-sent events, or other long-lived
requests), where the extra thread per request caps that concurrency.

You should do your own performance testing to see what effect ASGI versus WSGI
has on your code. In some cases, there may be a performance increase even for
a purely synchronous codebase under ASGI because the request-handling code is
still all running asynchronously. In general you will only want to enable ASGI
mode if you have asynchronous code in your project.

.. _async-handling-disconnect:

Handling disconnects
--------------------

For long-lived requests, a client may disconnect before the view returns a
response. In this case, an ``asyncio.CancelledError`` will be raised in the
view. You can catch this error and handle it if you need to perform any
cleanup::

    async def my_view(request):
        try:
            # Do some work
            ...
        except asyncio.CancelledError:
            # Handle disconnect
            raise

You can also :ref:`handle client disconnects in streaming responses
<request-response-streaming-disconnect>`.

.. _async-safety:

Async safety
============

.. envvar:: DJANGO_ALLOW_ASYNC_UNSAFE

Certain key parts of Django are not able to operate safely in an async
environment, as they have global state that is not coroutine-aware. These parts
of Django are classified as "async-unsafe", and are protected from execution in
an async environment. The synchronous API of the ORM is the main example, but
there are other parts that are also protected in this way.

If you try to run any of these parts from a thread where there is a *running
event loop*, you will get a
:exc:`~django.core.exceptions.SynchronousOnlyOperation` error. Note that you
don't have to be inside an async function directly to have this error occur. If
you have called a sync function directly from an async function,
without using :func:`sync_to_async` or similar, then it can also occur. This is
because your code is still running in a thread with an active event loop, even
though it may not be declared as async code.

If you encounter this error, you should fix your code to not call the offending
code from an async context. Instead, write your code that talks to async-unsafe
functions in its own, sync function, and call that using
:func:`asgiref.sync.sync_to_async` (or any other way of running sync code in
its own thread).

The async context can be imposed upon you by the environment in which you are
running your Django code. For example, Jupyter_ notebooks and IPython_
interactive shells both transparently provide an active event loop so that it
is easier to interact with asynchronous APIs.

If you're using an IPython shell, you can disable this event loop by running:

.. code-block:: shell

    %autoawait off

as a command at the IPython prompt. This will allow you to run synchronous code
without generating :exc:`~django.core.exceptions.SynchronousOnlyOperation`
errors; however, you also won't be able to ``await`` asynchronous APIs. To turn
the event loop back on, run:

.. code-block:: shell

    %autoawait on

If you're in an environment other than IPython (or you can't turn off
``autoawait`` in IPython for some reason), you are *certain* there is no chance
of your code being run concurrently, and you *absolutely* need to run your sync
code from an async context, then you can disable the warning by setting the
:envvar:`DJANGO_ALLOW_ASYNC_UNSAFE` environment variable to any value.

.. warning::

    If you enable this option and there is concurrent access to the
    async-unsafe parts of Django, you may suffer data loss or corruption. Be
    very careful and do not use this in production environments.

If you need to do this from within Python, do that with ``os.environ``::

    import os

    os.environ["DJANGO_ALLOW_ASYNC_UNSAFE"] = "true"

.. _Jupyter: https://jupyter.org/
.. _IPython: https://ipython.org

Async adapter functions
=======================

It is necessary to adapt the calling style when calling sync code from an async
context, or vice-versa. For this there are two adapter functions, from the
``asgiref.sync`` module: :func:`async_to_sync` and :func:`sync_to_async`. They
are used to transition between the calling styles while preserving
compatibility.

These adapter functions are widely used in Django. The :pypi:`asgiref` package
itself is part of the Django project, and it is automatically installed as a
dependency when you install Django with ``pip``.

``async_to_sync()``
-------------------

.. function:: async_to_sync(async_function, force_new_loop=False)

Takes an async function and returns a sync function that wraps it. Can be used
as either a direct wrapper or a decorator::

    from asgiref.sync import async_to_sync


    async def get_data(): ...


    sync_get_data = async_to_sync(get_data)


    @async_to_sync
    async def get_other_data(): ...

The async function is run in the event loop for the current thread, if one is
present. If there is no current event loop, a new event loop is spun up
specifically for the single async invocation and shut down again once it
completes. In either situation, the async function will execute on a different
thread to the calling code.

Threadlocals and contextvars values are preserved across the boundary in both
directions.

:func:`async_to_sync` is essentially a more powerful version of the
:func:`asyncio.run` function in Python's standard library. As well as ensuring
threadlocals work, it also enables the ``thread_sensitive`` mode of
:func:`sync_to_async` when that wrapper is used below it. In the cold path
(no running event loop) it pays the cost of starting a fresh event loop, like
:func:`asyncio.run`; when an event loop is already running (the in-request ASGI
case), the running loop is reused and the cost drops accordingly.

``sync_to_async()``
-------------------

.. 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, thread_sensitive=False)
    async_function = sync_to_async(sensitive_sync_function, thread_sensitive=True)


    @sync_to_async
    def sync_function(): ...

Threadlocals and contextvars values are preserved across the boundary in both
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=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=False``: the sync function will run in a brand new thread
  which is then closed once the invocation completes.

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*
:func:`async_to_sync` *above it in the stack* to correctly run things on the
main thread. If you use ``asyncio.run()`` or similar, it will fall back to
running thread-sensitive functions in a single, shared thread, but this will
not be the main thread.

The reason this is needed in Django is that many libraries, specifically
database adapters, require that they are accessed in the same thread that they
were created in. Also a lot of existing Django code assumes it all runs in the
same thread, e.g. middleware adding things to a request for later use in views.

Rather than introduce potential compatibility issues with this code, we instead
opted to add this mode so that all existing Django sync code runs in the same
thread and thus is fully compatible with async mode. Note that sync code will
always be in a *different* thread to any async code that is calling it, so you
should avoid passing raw database handles or other thread-sensitive references
around.

Within a single request, multiple ``thread_sensitive`` calls serialize on that
request's worker thread, but each request gets its own per-context worker, so
concurrent requests do *not* serialize against each other. This mirrors
Django's connection-per-thread model, and the same constraint applies in other
async database libraries, where concurrent queries on a single connection
serialize on a lock. To support more concurrent requests, increase the
connection pool size accordingly rather than disabling ``thread_sensitive``.

In practice this restriction means that you should not pass features of the
database ``connection`` object when calling ``sync_to_async()``. Doing so will
trigger the thread safety checks:

.. code-block:: pycon

    # DJANGO_SETTINGS_MODULE=settings.py python -m asyncio
    >>> import asyncio
    >>> from asgiref.sync import sync_to_async
    >>> from django.db import connection
    >>> # In an async context so you cannot use the database directly:
    >>> connection.cursor()
    django.core.exceptions.SynchronousOnlyOperation: You cannot call this from
    an async context - use a thread or sync_to_async.
    >>> # Nor can you pass resolved connection attributes across threads:
    >>> await sync_to_async(connection.cursor)()
    django.db.utils.DatabaseError: DatabaseWrapper objects created in a thread
    can only be used in that same thread. The object with alias 'default' was
    created in thread id 4371465600 and this is thread id 6131478528.

Rather, you should encapsulate all database access within a helper function
that can be called with ``sync_to_async()`` without relying on the connection
object in the calling code.
