asgi lifespan 是服务器启动/关闭时强制调用的生命周期钩子,必须实现为异步生成器,仅 yield 两次以分别表示 startup 和 shutdown 完成,否则将报错或导致资源泄漏。

asgi lifespan 是什么,什么时候必须实现
它不是可选装饰,而是 ASGI 服务器(如 Uvicorn、Hypercorn)启动/关闭时强制调用的生命周期钩子。如果你的应用需要在服务启动时初始化数据库连接池、加载配置或预热缓存,又或者要在退出前优雅关闭连接、刷写日志,lifespan 就是唯一标准入口。没实现它,Uvicorn 启动时会报 TypeError: lifespan handler not implemented;强行忽略,资源泄漏几乎必然发生。
怎么写一个合规的 lifespan handler
必须是异步可调用对象,接收一个 scope 字典,返回一个异步生成器(async def + yield),且只 yield 两次:第一次表示 startup 完成,第二次表示 shutdown 完成。任何偏离这个协议的行为都会导致服务器卡死或直接崩溃。
常见错误现象: 写成普通函数、漏掉 yield、yield 超过两次、startup 中抛异常没捕获、shutdown 里 await 了未完成的协程
- 使用
async def lifespan(app),不是def或lambda -
scope["type"]一定是"lifespan",别和http或websocket混淆 - startup 阶段失败必须抛出异常(让服务器 abort),不能静默吞掉;shutdown 阶段异常会被忽略,但应尽量避免
- 不要在 lifespan 里做耗时同步操作(如
time.sleep(5)),会阻塞整个事件循环
示例片段:
立即学习“Python免费学习笔记(深入)”;
LuckMall 是一款 100% 开放源码的 PHP 商城系统,基于 ThinkPHP5 开发,容易扩展,且具有强大的负载能力和稳定性。LuckMall 基于 Apache2.0 开源协议发布,免费且不限制商业使用。用户可以自由修改,打造符合自己意愿的电商平台。
async def lifespan(app):
# startup
await database.connect()
yield
# shutdown
await database.disconnect()Uvicorn 启动时 lifespan 不触发?检查这三处
不是代码写错,而是运行环境没对齐。最常踩的坑是:你以为在跑 ASGI,其实启动的是 WSGI 模式,或者用了错误的入口参数。
- 确保启动命令显式指定
--lifespan on(Uvicorn 0.20+ 默认是on,但老版本或某些 CI 环境可能关着) - 确认 ASGI 应用对象暴露的是
app(或你命名的变量),而不是app.app或application—— 错的变量名会让 Uvicorn 找不到lifespan协议 - 检查是否误用了
uvicorn.run(..., loop="asyncio")之类的老参数,新版本已弃用;正确方式是直接传app和host/port
验证方法:加一行 print("lifespan started") 在 yield 前,启动时没输出,基本就是上述某处断开了。
多个 lifespan handler 怎么组合?别手动链式调用
ASGI 规范不支持多个并列的 lifespan handler。如果你用了 Starlette、FastAPI 或自定义中间件,它们内部可能已注册了自己的 lifespan 逻辑。硬写两个 async def lifespan 并试图 yield 来回切换,结果是服务器拒绝启动或行为不可预测。
正确做法是:只保留一个顶层 handler,在里面显式 await 其他组件的初始化/清理逻辑。
- Starlette 的
on_event("startup")和on_event("shutdown")已被标记为 deprecated,必须迁移到 lifespan - FastAPI 的
@app.on_event("startup")底层仍是封装 lifespan,但仅限于 FastAPI 实例自身;若你还套了一层 middleware 或自定义 app 类,得自己合并逻辑 - 数据库连接池(如 asyncpg、Tortoise)通常提供
.init()/.close_connections()方法,直接 await 它们即可,别再包一层asyncio.create_task
复杂点在于:有些库的 cleanup 是“尽力而为”型(比如不保证 flush 日志),而 ASGI lifespan shutdown 阶段一旦 yield,服务器就认为你已完成——没做完的,就真做不完了。









