You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在使用lifespan的FastAPI中添加shutdown事件?

解决FastAPI中Lifespan与Profiler Shutdown事件冲突的问题

当FastAPI使用lifespan管理数据库等资源时,Starlette会忽略通过add_event_handler添加的shutdown事件,导致PyInstrumentProfiler无法正常导出结果。以下是几种可行的解决方案:

方案一:将Profiler关闭逻辑集成到自定义Lifespan函数

这是最直接且符合Starlette设计规范的方式,把Profiler的结果导出逻辑嵌入你已有的lifespan关闭阶段:

from fastapi import FastAPI
from contextlib import asynccontextmanager

@asynccontextmanager
async def lifespan(app: FastAPI):
    # 原有启动逻辑:初始化数据库连接等
    yield
    # 新增Profiler结果导出逻辑
    for middleware in app.user_middleware:
        if middleware.cls.__name__ == "PyInstrumentProfilerMiddleware":
            # 获取Profiler中间件实例并调用导出方法
            await middleware.cls.get_profiler_result()  # 同步方法则去掉await
            break

app = FastAPI(lifespan=lifespan)
app.add_middleware(PyInstrumentProfilerMiddleware, 
                   profiler_output_type="html", 
                   open_in_browser=True)

注意:需确认get_profiler_result是同步还是异步方法,同步方法直接调用即可,异步方法需添加await。

方案二:修改Profiler中间件以支持Lifespan事件

如果不想改动原有lifespan函数,可以修改PyInstrumentProfilerMiddleware的__call__方法,使其正确捕获ASGI Lifespan的shutdown事件:

class PyInstrumentProfilerMiddleware:
    # 保留原有初始化等代码...
    
    async def __call__(self, scope, receive, send):
        if scope["type"] == "lifespan":
            while True:
                message = await receive()
                if message["type"] == "lifespan.shutdown":
                    # 触发Profiler结果导出
                    await self.get_profiler_result()  # 同步方法去掉await
                    await send({"type": "lifespan.shutdown.complete"})
                    return
                elif message["type"] == "lifespan.startup":
                    await send({"type": "lifespan.startup.complete"})
        else:
            # 保留原有请求处理逻辑
            await self.app(scope, receive, send)

使用修改后的中间件,即可在应用关闭时自动触发Profiler结果导出,且不影响原有lifespan逻辑。

方案三:全局依赖项钩子(备选)

如果以上方案不适用,可通过全局依赖项添加shutdown逻辑(注:此方式针对每个请求结束触发,非全局应用关闭):

from fastapi import Depends

async def profiler_shutdown_hook():
    yield
    # 导出Profiler结果
    await app.state.profiler.get_profiler_result()

app = FastAPI(lifespan=lifespan)
app.add_middleware(PyInstrumentProfilerMiddleware, 
                   profiler_output_type="html", 
                   open_in_browser=True)
# 注册全局依赖
app.router.dependencies.append(Depends(profiler_shutdown_hook))

内容的提问来源于stack exchange,提问作者serendipty01

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 10:46:21