From cbee872fd4b8d33981407590397872fbaf8be6b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sun, 21 Sep 2025 18:25:01 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=92=A1=20Update=20comment=20explaining=20?= =?UTF-8?q?AsyncExitStack=20middleware?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- fastapi/applications.py | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/fastapi/applications.py b/fastapi/applications.py index e10aa5f90..9324ea33f 100644 --- a/fastapi/applications.py +++ b/fastapi/applications.py @@ -1013,26 +1013,28 @@ class FastAPI(Starlette): Middleware( ExceptionMiddleware, handlers=exception_handlers, debug=debug ), - # Add FastAPI-specific AsyncExitStackMiddleware for dependencies with - # contextvars. + # Add FastAPI-specific AsyncExitStackMiddleware for closing files. + # Before this was also used for closing dependencies with yield but + # those now have their own AsyncExitStack, to properly support + # streaming responses while keeping compatibility with the previous + # versions (as of writing 0.117.1) that allowed doing + # except HTTPException inside a dependency with yield. + # This needs to happen after user middlewares because those create a # new contextvars context copy by using a new AnyIO task group. - # The initial part of dependencies with 'yield' is executed in the - # FastAPI code, inside all the middlewares. However, the teardown part - # (after 'yield') is executed in the AsyncExitStack in this middleware. + + # This AsyncExitStack preserves the context for contextvars, not + # strictly necessary for closing files but it was one of the original + # intentions. # If the AsyncExitStack lived outside of the custom middlewares and - # contextvars were set in a dependency with 'yield' in that internal - # contextvars context, the values would not be available in the - # outer context of the AsyncExitStack. + # contextvars were set, for example in a dependency with 'yield' + # in that internal contextvars context, the values would not be + # available in the outer context of the AsyncExitStack. + # By placing the middleware and the AsyncExitStack here, inside all - # user middlewares, the code before and after 'yield' in dependencies - # with 'yield' is executed in the same contextvars context. Thus, all values - # set in contextvars before 'yield' are still available after 'yield,' as - # expected. - # Additionally, by having this AsyncExitStack here, after the - # ExceptionMiddleware, dependencies can now catch handled exceptions, - # e.g. HTTPException, to customize the teardown code (e.g. DB session - # rollback). + # user middlewares, the same context is used. + # This is currently not needed, only for closing files, but used to be + # important when dependencies with yield were closed here. Middleware(AsyncExitStackMiddleware), ] )