teardown_appcontext 是唯一覆盖所有退出路径的机制,必须注册该钩子并按序调用 db.session.remove() 和 db.engine.dispose(),不可依赖 atexit 或 teardown_request。

Flask 应用 shutdown 时 db.engine.dispose() 不触发?检查 teardown_appcontext 是否注册
直接在 app.run() 后写 db.engine.dispose() 没用——Werkzeug 开发模式会 fork 子进程,Gunicorn/Uvicorn 是多 worker 模型,主进程退出 ≠ 所有连接释放。唯一覆盖所有退出路径(HTTP 请求、flask shell、flask init-db CLI 命令、后台任务)的机制是 teardown_appcontext。
常见错误:误用 teardown_request,它只在请求上下文结束时触发,而 CLI 场景根本没有 request context。
-
teardown_appcontext在每次应用上下文销毁时执行,包括请求结束、命令执行完、甚至测试 tearDown - 必须同时调用
db.session.remove()和db.engine.dispose(),顺序不能反:先清理 session 实例,再关闭连接池 - 若用 Flask-SQLAlchemy,
db对象通常已绑定 engine 和 session,但需确认hasattr(db, 'engine')再调用,避免 AttributeError
@app.teardown_appcontext
def shutdown_session(exception=None):
if hasattr(db, 'session'):
db.session.remove()
if hasattr(db, 'engine'):
db.engine.dispose()
生产环境数据库连接池卡死?pool_pre_ping 不等于自动释放
很多人开了 "pool_pre_ping": True 就以为连接管理“全自动”了。它只在每次从池里取连接前做一次简单 ping,失败则丢弃该连接并新建一个——这解决的是数据库主动断连后的自动恢复,不是应用退出时的资源清理。
真正导致僵死连接的,是连接池缓存未清空、空闲连接滞留、或服务端(如 PostgreSQL 的 tcp_keepalives_idle、MySQL 的 wait_timeout)静默断开后池内连接仍被复用。
立即学习“Python免费学习笔记(深入)”;
python-docx Skill功能概述python-docx Skill是一项面向实际任务的技能,主要用于本Skill提供使用python-docx生成专业Word文档的标准方法和最佳实践;生成安全服务方案文档;核心要点生成技术架构设计文档;生成任何需要专业排版的Word文档;核心库 : python-docx;使用与执行辅助库 : docx.shared , docx.enum , docx.oxml.ns;标准代码模板;1. 文档初始化;2. 字体设置(必须!它将相关步骤、工具调用和结果整理方式集
- 必须配
pool_recycle=3600(单位秒),强制连接定期刷新,与数据库服务端超时对齐 - psycopg2 直连时,在 URL 中加
options='-c statement_timeout=30000'防查询挂死拖垮整个池 - 高并发场景下,单连接 +
teardown_appcontext会成瓶颈;连接池是刚需,不是可选项
Gunicorn 主进程收不到 SIGTERM?验证 master-worker 模式是否生效
优雅停机的前提是存在长期存活的 master 进程来协调新旧 worker 切换。如果 ps aux | grep gunicorn 只看到一堆独立进程、没有带 master 字样的父进程,说明 HUP 或 SIGTERM 根本没地方发。
常见配置陷阱:
- 用了
--preload但没配pidfile,导致发信号时找不到 master PID -
graceful-timeout设太小(默认 30 秒),长请求还没处理完就被强制 kill -
timeout≤graceful-timeout,worker 在等待 graceful 关闭时先因超时被干掉
推荐做法:在 gunicorn.conf.py 固定写 pidfile = "/var/run/gunicorn.pid",发信号前先 kill -0 $(cat /var/run/gunicorn.pid) 确认进程存活。
atexit.register() 是补充,不是替代
atexit.register() 能在 Python 解释器正常退出前执行函数,适合关文件句柄、刷日志缓冲区等操作。但它不响应 kill -9,也不保证在所有 worker 进程中都执行——Gunicorn 的每个 worker 是独立 Python 进程,atexit 只对当前进程有效。
更关键的是:它无法替代 teardown_appcontext。因为 atexit 触发时机晚于所有上下文钩子,此时 db 对象可能已被 GC、session 已解绑、engine 引用已失效。
- 不要在
atexit里调用db.session.close()或db.engine.dispose()—— 极大概率报AttributeError或静默失败 - 适合放的逻辑:写 final status log、
psutil.Process().cpu_percent()快照、清理临时目录 - 若真要用,确保函数内所有对象都是全局且生命周期覆盖到 exit 阶段
flask run 测试通过的 teardown_appcontext,上线 Gunicorn 后若没验证 master 进程是否存在、没调大 graceful-timeout,照样会连接泄漏。

















