From c3f54a0794d8acadb0059c55edbb314678253921 Mon Sep 17 00:00:00 2001 From: Casper da Costa-Luis Date: Fri, 27 Feb 2026 19:12:46 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=9D=20Add=20`await`=20in=20`StreamingR?= =?UTF-8?q?esponse`=20code=20example=20to=20allow=20cancellation=20(#14681?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- docs/en/docs/advanced/custom-response.md | 12 +++++++++++- docs_src/custom_response/tutorial007_py310.py | 2 ++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/en/docs/advanced/custom-response.md b/docs/en/docs/advanced/custom-response.md index e88e958657..823ee5ff2c 100644 --- a/docs/en/docs/advanced/custom-response.md +++ b/docs/en/docs/advanced/custom-response.md @@ -167,7 +167,17 @@ You can also use the `status_code` parameter combined with the `response_class` Takes an async generator or a normal generator/iterator and streams the response body. -{* ../../docs_src/custom_response/tutorial007_py310.py hl[2,14] *} +{* ../../docs_src/custom_response/tutorial007_py310.py hl[3,16] *} + +/// note | Technical Details + +An `async` task can only be cancelled when it reaches an `await`. If there is no `await`, the generator (function with `yield`) can not be cancelled properly and may keep running even after cancellation is requested. + +Since this small example does not need any `await` statements, we add an `await anyio.sleep(0)` to give the event loop a chance to handle cancellation. + +This would be even more important with large or infinite streams. + +/// #### Using `StreamingResponse` with file-like objects { #using-streamingresponse-with-file-like-objects } diff --git a/docs_src/custom_response/tutorial007_py310.py b/docs_src/custom_response/tutorial007_py310.py index e2a53a2119..f8dd9f895d 100644 --- a/docs_src/custom_response/tutorial007_py310.py +++ b/docs_src/custom_response/tutorial007_py310.py @@ -1,3 +1,4 @@ +import anyio from fastapi import FastAPI from fastapi.responses import StreamingResponse @@ -7,6 +8,7 @@ app = FastAPI() async def fake_video_streamer(): for i in range(10): yield b"some fake video bytes" + await anyio.sleep(0) @app.get("/")