diff options
| author | Carlton Gibson <carlton.gibson@noumenal.es> | 2022-12-13 16:15:25 +0100 |
|---|---|---|
| committer | Carlton Gibson <carlton.gibson@noumenal.es> | 2022-12-22 10:41:12 +0100 |
| commit | 0bd2c0c9015b53c41394a1c0989afbfd94dc2830 (patch) | |
| tree | 6b24758335cf10eeedfdf7dec50cda3500796305 /docs/ref/request-response.txt | |
| parent | ae0899be0d787fbfc5f5ab2b18c5a8219d822d2b (diff) | |
Fixed #33735 -- Added async support to StreamingHttpResponse.
Thanks to Florian Vazelle for initial exploratory work, and to Nick
Pope and Mariusz Felisiak for review.
Diffstat (limited to 'docs/ref/request-response.txt')
| -rw-r--r-- | docs/ref/request-response.txt | 88 |
1 files changed, 70 insertions, 18 deletions
diff --git a/docs/ref/request-response.txt b/docs/ref/request-response.txt index 34a31c4936..ebcd9ee523 100644 --- a/docs/ref/request-response.txt +++ b/docs/ref/request-response.txt @@ -1116,43 +1116,76 @@ parameter to the constructor method:: .. class:: StreamingHttpResponse The :class:`StreamingHttpResponse` class is used to stream a response from -Django to the browser. You might want to do this if generating the response -takes too long or uses too much memory. For instance, it's useful for -:ref:`generating large CSV files <streaming-csv-files>`. +Django to the browser. -.. admonition:: Performance considerations +.. admonition:: Advanced usage - Django is designed for short-lived requests. Streaming responses will tie - a worker process for the entire duration of the response. This may result - in poor performance. + :class:`StreamingHttpResponse` is somewhat advanced, in that it is + important to know whether you'll be serving your application synchronously + under WSGI or asynchronously under ASGI, and adjust your usage + appropriately. - Generally speaking, you should perform expensive tasks outside of the - request-response cycle, rather than resorting to a streamed response. + Please read these notes with care. + +An example usage of :class:`StreamingHttpResponse` under WSGI is streaming +content when generating the response would take too long or uses too much +memory. For instance, it's useful for :ref:`generating large CSV files +<streaming-csv-files>`. + +There are performance considerations when doing this, though. Django, under +WSGI, is designed for short-lived requests. Streaming responses will tie a +worker process for the entire duration of the response. This may result in poor +performance. + +Generally speaking, you would perform expensive tasks outside of the +request-response cycle, rather than resorting to a streamed response. + +When serving under ASGI, however, a :class:`StreamingHttpResponse` need not +stop other requests from being served whilst waiting for I/O. This opens up +the possibility of long-lived requests for streaming content and implementing +patterns such as long-polling, and server-sent events. + +Even under ASGI note, :class:`StreamingHttpResponse` should only be used in +situations where it is absolutely required that the whole content isn't +iterated before transferring the data to the client. Because the content can't +be accessed, many middleware can't function normally. For example the ``ETag`` +and ``Content-Length`` headers can't be generated for streaming responses. The :class:`StreamingHttpResponse` is not a subclass of :class:`HttpResponse`, because it features a slightly different API. However, it is almost identical, with the following notable differences: -* It should be given an iterator that yields bytestrings as content. +* It should be given an iterator that yields bytestrings as content. When + serving under WSGI, this should be a sync iterator. When serving under ASGI, + this is should an async iterator. * You cannot access its content, except by iterating the response object - itself. This should only occur when the response is returned to the client. + itself. This should only occur when the response is returned to the client: + you should not iterate the response yourself. + + Under WSGI the response will be iterated synchronously. Under ASGI the + response will be iterated asynchronously. (This is why the iterator type must + match the protocol you're using.) + + To avoid a crash, an incorrect iterator type will be mapped to the correct + type during iteration, and a warning will be raised, but in order to do this + the iterator must be fully-consumed, which defeats the purpose of using a + :class:`StreamingHttpResponse` at all. * It has no ``content`` attribute. Instead, it has a - :attr:`~StreamingHttpResponse.streaming_content` attribute. + :attr:`~StreamingHttpResponse.streaming_content` attribute. This can be used + in middleware to wrap the response iterable, but should not be consumed. * You cannot use the file-like object ``tell()`` or ``write()`` methods. Doing so will raise an exception. -:class:`StreamingHttpResponse` should only be used in situations where it is -absolutely required that the whole content isn't iterated before transferring -the data to the client. Because the content can't be accessed, many -middleware can't function normally. For example the ``ETag`` and -``Content-Length`` headers can't be generated for streaming responses. - The :class:`HttpResponseBase` base class is common between :class:`HttpResponse` and :class:`StreamingHttpResponse`. +.. versionchanged:: 4.2 + + Support for asynchronous iteration was added. + Attributes ---------- @@ -1181,6 +1214,16 @@ Attributes This is always ``True``. +.. attribute:: StreamingHttpResponse.is_async + + .. versionadded:: 4.2 + + Boolean indicating whether :attr:`StreamingHttpResponse.streaming_content` + is an asynchronous iterator or not. + + This is useful for middleware needing to wrap + :attr:`StreamingHttpResponse.streaming_content`. + ``FileResponse`` objects ======================== @@ -1213,6 +1256,15 @@ a file open in binary mode like so:: The file will be closed automatically, so don't open it with a context manager. +.. admonition:: Use under ASGI + + Python's file API is synchronous. This means that the file must be fully + consumed in order to be served under ASGI. + + In order to stream a file asynchronously you need to use a third-party + package that provides an asynchronous file API, such as `aiofiles + <https://github.com/Tinche/aiofiles>`_. + Methods ------- |
