当前位置: 首页 > news >正文

App Runner和Task Pipeline中的数据库连接管理指南

由于 App Runner 中存在一些需要长时间执行的任务,如大语言模型(LLM)生成和外部请求,Flask-Sqlalchemy 的数据库连接池策略是每个请求分配一个连接(事务)。这种方式会导致在执行非数据库任务时,连接仍然被占用,进而在高并发请求时,由于多个长时间运行的任务,无法获取新的连接。

因此,App Runner 和任务管道中的数据库操作必须确保在使用后立即关闭连接,建议传递 ID 而不是 Model 对象,以避免分离(deattach)错误。

一.Flask-SQLAlchemy数据库连接池策略

Flask-SQLAlchemy 的默认行为是每个请求分配一个数据库连接,连接在请求期间保持打开状态,并在请求结束时关闭。这个设计在大多数情况下是合理的,因为 HTTP 请求通常是短时间的操作。然而,当涉及到长时间运行的任务(例如 LLM 生成或外部 API 请求)时,如果数据库连接一直保持打开状态,这就会导致资源浪费,尤其是在高并发的情况下,可能会耗尽连接池,进而引发连接不可用的问题。

1.每个请求分配一个连接

每个请求到来时,Flask-SQLAlchemy 会从连接池中分配一个数据库连接。这意味着当 Flask 处理一个 HTTP 请求时,一个连接会被分配给该请求,直到请求处理完成才会释放。

2.连接在长时间任务中被占用

如果在一个请求中,有一部分任务是非数据库相关的(如大语言模型生成、等待外部 API 响应等),数据库连接会在整个任务执行期间都被占用,尽管这些任务并不需要使用数据库。

3.高并发下连接耗尽

在高并发情况下,如果多个请求同时执行长时间任务,数据库连接池的连接可能会耗尽,导致新的请求无法获取连接,最终出现数据库连接失败的情况。

二.创建新记录

1.默认行为

假设有一个 HTTP 请求需要创建一个新记录并执行一个长时间运行的任务:

@app.route('/create', methods=['POST'])
def create_app():app = App(id=1)db.session.add(app)db.session.commit()db.session.refresh(app)  # 获取创建时数据库的默认值# 模拟一个长时间任务,例如 LLM 生成或外部 API 请求time.sleep(30)# 完成后返回结果return app.id

在这个代码中:

  • 数据库连接在请求开始时被分配,插入了一条新记录,并提交到数据库。

  • 然后进入一个长时间运行的任务,使用 time.sleep(30) 来模拟实际场景中的等待。

  • 即便在这段时间内不需要数据库操作,数据库连接仍然保持打开状态,直到整个请求处理结束。

问题: 如果同时有多个类似请求(例如高并发下多个用户发起类似操作),那么数据库连接池中的连接会被迅速耗尽,因为每个请求的连接在长时间任务期间无法释放,新的请求无法获取连接。

2.解决方案

为了避免这种情况,应该在完成数据库操作后立即关闭连接,将长时间运行的任务与数据库操作隔离开。这可以通过显式关闭 db.session 来实现:

@app.route('/create', methods=['POST'])
def create_app():# 创建新记录并提交app = App(id=1)db.session.add(app)db.session.commit()db.session.refresh(app)  # 获取数据库中的默认值db.session.close()  # 立即关闭连接# 模拟一个长时间任务,例如 LLM 生成或外部 API 请求time.sleep(30)# 完成后返回结果return app.id

在这个代码中:

  • 数据库的操作完成后立即调用 db.session.close(),释放连接。

  • 后续的长时间任务在连接已经关闭的情况下执行,不会占用数据库连接资源。

  • 即使在高并发情况下,也不会因为长时间任务而导致连接池耗尽。

二.从表中获取记录

1.默认行为

对于查询操作,问题类似。假设要从数据库中查询记录,然后执行一个长时间的任务:

@app.route('/fetch', methods=['GET'])
def fetch_app():app = db.session.query(App).filter(App.id == 1).first()# 在查询到记录后进行长时间任务time.sleep(30)return app.created_at

在这个例子中,数据库连接在 db.session.query 之后仍然保持打开,直到请求结束。

2.解决方案

可在完成查询操作后立即关闭连接,再处理长时间任务:

@app.route('/fetch', methods=['GET'])
def fetch_app():app = db.session.query(App).filter(App.id == 1).first()created_at = app.created_atdb.session.close()  # 立即关闭连接# 处理长时间任务time.sleep(30)return created_at

通过这样做,数据库连接仅在需要的时候被占用,其他长时间任务不会占用连接池资源,确保高并发时请求能顺利执行。

三.更新表字段

1.默认行为

以下是一个常见的更新表字段的操作,连接池可能会在不必要的时间段被占用:

@app.route('/update', methods=['POST'])
def update_app():# 根据 id 获取记录app = db.session.query(App).filter(App.id == 1).first()# 更新字段app.updated_at = time.utcnow()db.session.commit()  # 提交更新# 模拟长时间任务time.sleep(30)return app.id

在这个例子中:

  • 首先从数据库中查询出一个 App 记录。

  • 然后更新 updated_at 字段,并提交更新操作。

  • 之后再执行一个长时间的任务(用 time.sleep(30) 来模拟)。

问题: 数据库连接在整个请求期间被占用,直到请求结束时才释放。尤其是长时间任务的存在,可能导致其他请求无法及时获取连接,出现连接池耗尽的问题。

2.解决方案

通过在更新数据库字段后立即关闭数据库连接,可以避免连接池资源被不必要地占用。

@app.route('/update', methods=['POST'])
def update_app():# 根据 id 获取记录app = db.session.query(App).filter(App.id == 1).first()# 更新字段app.updated_at = time.utcnow()db.session.commit()  # 提交更新# 在更新后立即关闭数据库连接db.session.close()# 模拟长时间任务time.sleep(30)return app.id

在这个改进的代码中:

  • 在更新 updated_at 字段后,立即调用 db.session.close() 关闭数据库连接。

  • 后续的长时间任务与数据库连接无关,因此不会占用连接池资源。

四.注意事项

Flask-SQLAlchemy 的默认行为会在长时间任务中保留数据库连接,从而导致连接池资源紧张。通过在数据库操作后立即关闭连接,能够避免这种问题,确保在高并发请求时,数据库连接池的资源被合理使用。通过这种方式,可以确保数据库连接池的资源得到合理利用,在高并发的情况下依然能够正常处理请求。

1.及时关闭连接

数据库操作(包括更新、插入和查询)结束后,尽量及时关闭连接,以便连接池中的连接能被其他请求使用。

2.长时间任务处理

长时间任务(如外部 API 请求、文件处理等)最好在数据库操作完成并关闭连接后再进行,以避免不必要的资源占用。

参考文献

[1] dify-0.7.2\api\core\app\apps\README.md 4

[2] App Runner和Task Pipeline中的数据库连接管理指南:https://z0yrmerhgi8.feishu.cn/wiki/AUNDwcmuKihmRjk9O1YcZrAdnZy

http://www.xdnf.cn/news/671995.html

相关文章:

  • 【数据结构】树形结构--二叉树
  • U-Boot ARMv8 平台异常处理机制解析
  • Android studio 查看aar源码出现/* compiled code */
  • 基于 MindQuantum 记录线路作用下基底态的变化过程
  • 让jupyter notebook显示目录
  • 大模型应用:开发移动端页面个人中心页面提示词
  • 基于大模型预测视神经脊髓炎的技术方案大纲
  • Ubuntu 20.04 下 OpenCV 4.5.4 编译安装与系统默认 OpenCV 4.2 共存切换指南【2025最新版!!!】
  • Elasticsearch创建快照仓库报错处理
  • 嵌入式学习--江协stm32day3
  • 阿里云服务器采用crontab定时任务使acme.sh全自动化申请续签免费SSL证书,并部署在Linux宝塔网站和雷池WAF
  • 基于递归思想的系统架构图自动化生成实践
  • VMware-MySQL主从
  • AI提示工程(Prompt Engineering)高级技巧详解
  • 【大模型实战篇】BGE-Rerank-base重排服务部署教程
  • AI前端开发岗位面试准备指南
  • 什么是数据驱动?以及我们应如何理解数据驱动?
  • 什么是可重组机器人?
  • 33. 自动化测试开发之使用mysql异步连接池实现mysql数据库操作
  • 前端域名、端口、协议一样,本地缓存可以共享吗?
  • 【b站计算机拓荒者】【2025】微信小程序开发教程 - chapter3 项目实践 - 2信息采集
  • Protocol Buffers 复杂嵌套编译指南:生成 C++ 代码
  • JavaScript- 3.2 JavaScript实现不同显示器尺寸的响应式主题和页面
  • 开源酷炫大数据可视化大屏html+eacher 100+套
  • 力扣热题——分类求和并作差
  • Vue-02 (使用不同的 Vue CLI 插件)
  • 从 PyTorch 到 TensorFlow Lite:模型训练与推理
  • 【华为云物联网】iOtDA数据以表格字段转发OBS的设置攻略,便于以后数据上大屏
  • 如何描述BUG
  • VUE项目部署IIS服务器手册