0

0

FastAPI 应用启动后执行一次性任务的正确姿势

DDD

DDD

发布时间:2025-11-01 14:09:00

|

781人浏览过

|

来源于php中文网

原创

FastAPI 应用启动后执行一次性任务的正确姿势

本文详细介绍了如何使用 fastapi 的 lifespan 事件结合 asynccontextmanager 在应用启动后、处理任何请求之前执行一次性初始化任务。通过此机制,开发者可以确保数据库连接、缓存预加载等操作在服务可用时已完成,同时避免阻塞服务器启动过程。

理解应用启动时的初始化需求

在构建基于 FastAPI 的 Web 服务时,我们经常需要在应用程序启动后、开始处理用户请求之前执行一些初始化操作。这些操作可能包括:

  • 加载配置数据
  • 建立数据库连接池
  • 预加载缓存数据
  • 启动后台任务或消费者
  • 执行其他一次性设置逻辑

直接在 if __name__ == "__main__": 块中调用这些函数,如果放在 uvicorn.run(app) 之前,会阻塞服务器启动,导致服务无法及时响应;如果放在 uvicorn.run(app) 之后,则根本不会被执行,因为 uvicorn.run(app) 是一个阻塞调用,会一直运行直到服务器关闭。因此,我们需要一个机制,让 FastAPI 框架自身来管理这些启动事件。

FastAPI 的 Lifespan 事件管理

FastAPI 提供了 lifespan 事件管理机制,它基于 Python 的 contextlib.asynccontextmanager,允许开发者定义在应用启动和关闭时执行的异步代码。这是处理一次性初始化任务的官方推荐方式。

lifespan 的核心思想是定义一个异步上下文管理器。当应用启动时,上下文管理器会执行 yield 语句之前的代码;当应用准备好接收请求时,它会 yield 控制权,此时服务开始处理请求;当应用关闭时,它会执行 yield 语句之后(即上下文退出时)的代码,用于资源清理。

示例:在 FastAPI 启动后初始化数据

假设我们有一个需求,在 FastAPI 应用启动后,需要执行一个耗时操作(例如,模拟数据加载),然后初始化一个全局变量 DATA。

import time
import uvicorn
from fastapi import FastAPI
from contextlib import asynccontextmanager

# 全局变量,用于存储初始化后的数据
DATA = {"value": ""}

def create_data():
    """
    模拟一个耗时的初始化函数,用于在应用启动时加载数据。
    """
    print("正在执行 create_data()...")
    time.sleep(2)  # 模拟耗时操作,例如从数据库加载数据或进行复杂的计算
    DATA["value"] = "Hello World!"
    print("create_data() 执行完毕。")

@asynccontextmanager
async def lifespan(app: FastAPI):
    """
    FastAPI 应用的生命周期管理器。
    在应用启动时执行 create_data(),并在应用关闭时执行清理操作(如果需要)。
    """
    # --- 应用启动时执行的代码 ---
    create_data()  # 在这里调用我们的初始化函数
    print("FastAPI 应用已启动,准备接收请求。")
    yield  # 应用在此处开始接收请求,yield 之前的代码在启动前完成
    # --- 应用关闭时执行的代码 ---
    print("FastAPI 应用正在关闭。")
    # 可以在这里执行清理操作,例如关闭数据库连接、释放资源等
    DATA["value"] = "" # 清理数据,模拟资源释放
    print("清理工作完成。")

# 将 lifespan 事件管理器传递给 FastAPI 应用
app = FastAPI(lifespan=lifespan)

@app.get("/")
def get_root():
    """
    一个简单的 GET 接口,返回 DATA 中存储的值。
    """
    return DATA

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)

代码解析

  1. from contextlib import asynccontextmanager: 导入 asynccontextmanager 装饰器,它是创建异步上下文管理器的关键。
  2. DATA = {"value": ""}: 定义一个全局字典,用于存储初始化后的数据。
  3. def create_data():: 这是一个普通函数,包含了我们希望在应用启动时执行的逻辑。这里模拟了数据加载的耗时操作。
  4. @asynccontextmanager: 这个装饰器将 lifespan 异步生成器函数转换为一个异步上下文管理器。
  5. async def lifespan(app: FastAPI)::
    • 这个异步函数是 lifespan 事件的核心。它接收 FastAPI 应用实例作为参数。
    • create_data(): 在 yield 语句之前,create_data() 函数会被调用。这意味着在 FastAPI 应用开始处理任何 HTTP 请求之前,create_data() 会先执行并完成。
    • yield: 这是上下文管理器的关键点。当执行到 yield 语句时,lifespan 函数会暂停,并将控制权交还给 FastAPI。此时,FastAPI 应用正式启动,可以开始接收并处理客户端请求。
    • yield 之后的代码会在应用关闭时执行。这提供了一个方便的钩子来执行清理工作,例如关闭数据库连接、释放内存等。
  6. app = FastAPI(lifespan=lifespan): 在创建 FastAPI 应用实例时,通过 lifespan 参数将我们定义的 lifespan 上下文管理器传递进去。FastAPI 会在内部管理这个生命周期事件。
  7. uvicorn.run(app): 正常启动 Uvicorn 服务器。此时,lifespan 中 yield 之前的代码(即 create_data())会先执行。

运行效果

当你运行上述代码时,你会观察到以下输出顺序:

Copy Leaks
Copy Leaks

AI内容检测和分级,帮助创建和保护原创内容

下载
正在执行 create_data()...
create_data() 执行完毕。
FastAPI 应用已启动,准备接收请求。
INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [xxxxx] using statreload
INFO:     Started server process [xxxxx]
INFO:     Waiting for application startup.
INFO:     Application startup complete.

然后,如果你访问 http://localhost:8000,你会得到 {"value": "Hello World!"},这证明 create_data() 已经成功执行并更新了 DATA 变量。

当你按下 CTRL+C 停止服务器时,你会看到:

INFO:     Shutting down
FastAPI 应用正在关闭。
清理工作完成。
INFO:     Finished server process [xxxxx]
INFO:     Stopped reloader process [xxxxx]

这表明 yield 之后的清理代码也得到了正确执行。

注意事项

  • 异步操作: 如果你的初始化函数 create_data 内部包含异步操作(例如 await 数据库查询、网络请求),那么 create_data 函数本身也应该是一个 async def 函数,并且在 lifespan 中调用时需要使用 await create_data()。
  • 错误处理: 在 lifespan 的启动阶段(yield 之前)如果发生未捕获的异常,FastAPI 应用将无法启动。因此,建议对关键的初始化逻辑进行适当的错误处理,例如使用 try...except 块。
  • 资源清理: yield 之后的代码块是执行资源清理的理想位置。确保在这里释放所有在启动阶段获取的资源,以避免内存泄漏或资源耗尽。
  • 全局状态管理: 尽管在 lifespan 中修改全局变量是可行的,但对于更复杂的应用,考虑使用依赖注入(Dependency Injection)或 FastAPI 的 app.state 来管理应用级别的状态,以提高代码的可维护性和可测试性。app.state 允许你在应用实例上直接存储和访问状态。

总结

通过 FastAPI 的 lifespan 事件结合 asynccontextmanager,我们可以优雅且高效地管理应用的启动和关闭事件。这种机制确保了在服务正式对外提供前,所有必要的初始化工作都能顺利完成,并且在服务关闭时能够进行必要的资源清理。掌握 lifespan 是构建健壮和可维护的 FastAPI 应用的关键一环。

相关专题

更多
python开发工具
python开发工具

php中文网为大家提供各种python开发工具,好的开发工具,可帮助开发者攻克编程学习中的基础障碍,理解每一行源代码在程序执行时在计算机中的过程。php中文网还为大家带来python相关课程以及相关文章等内容,供大家免费下载使用。

760

2023.06.15

python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

639

2023.07.20

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

762

2023.07.25

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

619

2023.07.31

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

1265

2023.08.03

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

549

2023.08.04

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

579

2023.08.04

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

709

2023.08.11

高德地图升级方法汇总
高德地图升级方法汇总

本专题整合了高德地图升级相关教程,阅读专题下面的文章了解更多详细内容。

72

2026.01.16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 4万人学习

Django 教程
Django 教程

共28课时 | 3.2万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号