From 4e85ad50c7e9f89b548304bdc5633613bebd9008 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Fri, 27 Feb 2026 17:43:53 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20Fix=20support=20for=20cancellati?= =?UTF-8?q?on=20without=20an=20extra=20await?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fastapi/routing.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/fastapi/routing.py b/fastapi/routing.py index aec4b5c3d1..f00cd2ca75 100644 --- a/fastapi/routing.py +++ b/fastapi/routing.py @@ -28,6 +28,7 @@ from typing import ( TypeVar, ) +import anyio from annotated_doc import Doc from fastapi import params from fastapi._compat import ( @@ -486,6 +487,9 @@ def get_request_handler( async def _async_stream_jsonl() -> AsyncIterator[bytes]: async for item in gen: yield _serialize_item(item) + # To allow for cancellation to trigger + # Ref: https://github.com/fastapi/fastapi/issues/14680 + await anyio.sleep(0) stream_content: AsyncIterator[bytes] | Iterator[bytes] = ( _async_stream_jsonl() @@ -507,6 +511,18 @@ def get_request_handler( elif dependant.is_async_gen_callable or dependant.is_gen_callable: # Raw streaming with explicit response_class (e.g. StreamingResponse) gen = dependant.call(**solved_result.values) + if dependant.is_async_gen_callable: + + async def _async_stream_raw( + async_gen: AsyncIterator[Any], + ) -> AsyncIterator[Any]: + async for chunk in async_gen: + yield chunk + # To allow for cancellation to trigger + # Ref: https://github.com/fastapi/fastapi/issues/14680 + await anyio.sleep(0) + + gen = _async_stream_raw(gen) response_args = _build_response_args( status_code=status_code, solved_result=solved_result )