news 2026/6/9 17:40:41

FastAPI 流式响应中,如何优雅处理客户端断连后的数据库操作?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
FastAPI 流式响应中,如何优雅处理客户端断连后的数据库操作?

问题出现过程

1. 客户端发起流式对话请求

我们从一个典型的流式对话接口开始。我们使用依赖注入来获取一个 SQLAlchemy 的 AsyncSession,在对话开始时创建消息,在对话结束后更新 AI 的回答。

流式对话原始代码(伪代码)

2. 客户端取消对话(主动断开)

当用户取消发送时,会抛出这个异常

pymysql.err.InterfaceError:

原因:当客户端断开时 ,FastAPI 会立即把它的 session连接回收掉,底层的那个物理连接被标记为 Cancelled,然后执行finally的时候,再往下传原来session连接就不对了,save_conversation函数就会抛pymysql.err.InterfaceError。

问题解决尝试

尝试一:在 save_conversation 函数中创建新连接

一个自然的想法是:既然旧的 session 不能用了,那就在保存的时候检查一下,如果不可用就创建一个新的。

代码更新

结果:失败! 没想到,即使创建了新的 session,依然抛出了 pymysql.err.InterfaceError。

原因分析:之所以还会抛错误,原因是这个新会话 依然在使用已经被取消的连接池资源,因为 FastAPI/Starlette 在主请求取消时,会把整个 AsyncSessionLocal() 对象的连接都标记为 “cancelled”。即便你重新 async with AsyncSessionLocal(),底层复用的还是同一个数据库连接池里的连接,而那个连接刚被 cancel。

重新创建个数据库引擎 是肯定可以的,但是只是对话后更新,这么搞完全没必要。

或者创建个独立线程,在新线程中去创建新连接,应该是可以的,个人还是感觉比较重,浪费资源。

尝试二:创建个协程去执行save_conversation

代码更新

疑惑点:asyncio.create_task 启动的协程仍然跑在同一个线程和进程里,也会复用那个全局的连接池,理论上确实还有可能拿到刚才那个被 cancel 的连接啊?

主要在于操作的时序和上下文隔离:

先清理,后执行

当原始请求被取消后,FastAPI 会立即开始清理与该请求相关的资源(包括回收它持有的数据库连接)。这个清理动作在 finally 块中调用 create_task 之前就已经触发了。我们派生出的后台任务是在这个清理逻辑之后才启动的。

上下文隔离

这个后台协程已经完全不挂在 HTTP 请求的上下文上了。客户端断开与否,都影响不了它的独立运行。只要连接池中还有任意一个好连接,它就能完成写入。

高成功率

因为顺序已经变成了:先断开、先清理 → 再新建、再执行,所以新任务向连接池请求时,拿到那个“坏掉”连接的概率已经大大降低。连接池会优先分配一个健康的、空闲的连接。

即使在极端情况下又拿到了旧连接,它也很有可能在 session.begin() 阶段就失败,我们还可以在后台任务的 try...except 块里加入重试逻辑(比如 await asyncio.sleep(0.1) 后重试),进一步提高健壮性。

大量测试后,发现真没问题😁。

结论

对于需要确保最终操作(如数据写入)一定执行的流式 API,asyncio.create_task 提供了一种轻量级且非常有效的解决方案。它避免了引入像 Celery 这样复杂的任务队列,同时优雅地解决了因客户端断连导致资源状态污染的问题。

通过将关键的收尾工作与不稳定的 HTTP 请求生命周期解耦,我们能构建出更加健壮和可靠的 FastAPI 应用。"

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/4 23:37:14

EmotiVoice语音合成冷热数据分离存储方案

EmotiVoice语音合成冷热数据分离存储方案 在当今智能语音服务快速普及的背景下,用户对语音自然度和情感表达的要求已远超“能听清”这一基本需求。从虚拟主播的情绪化播报,到AI客服中带有温度的回应,再到游戏NPC根据剧情动态切换语气——这些…

作者头像 李华
网站建设 2026/6/5 0:35:01

C语言初学笔记2---C语言常见概念

目录 10.转义字符1.学习\\? → 在书写连续多个问号时使用,防止他们被解析成三字母词2.学习 \\ → 输出单个和多个单引号 2.1输出单个单引号2.2输出多个单引号 3.学习 \\" → 输出单个和多个双引号 "3.1输出单个双引号3.2输出多个双引号 4.学习\\\ → 表示…

作者头像 李华
网站建设 2026/6/8 13:24:52

《自动控制原理》第 5 章 频率响应分析法:5.3、5.4、5.5

5.3 控制系统频率特性图的绘制控制系统的频率特性可视为由典型环节频率特性组合而成的。本节将在上一节讨论的基础之上,介绍复杂控制系统频率特性图的绘制问题。一般来说,上节所介绍的典型环节频率特性图的绘制方法,可以推广至复杂控制系统。…

作者头像 李华
网站建设 2026/6/5 4:03:49

Java毕设项目:基于JAVA的北京市公交管理系统基于Java+Vue+SpringBoot的北京市公交管理系统(源码+文档,讲解、调试运行,定制等)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

作者头像 李华
网站建设 2026/6/8 19:22:46

C++医学图像处理经典ITK库用法详解<三>: 图像配准模块功能

1、ITK库概述ITK (Insight Segmentation and Registration Toolkit) 是一个开源的跨平台软件开发工具包,主要用于图像处理,特别是生物医学图像处理领域。该工具包提供了一套丰富的图像处理算法,特别是在图像分割和配准方面具有强大的功能。IT…

作者头像 李华