Django 长耗时任务,调用 ORM 时会出现"MySQL server has gone away"问题如何解决? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
a663
V2EX    Python

Django 长耗时任务,调用 ORM 时会出现"MySQL server has gone away"问题如何解决?

  •  
  •   a663 122 天前 1830 次点击
    这是一个创建于 122 天前的主题,其中的信息可能已经有所发展或是发生改变。

    当 Django 结合异步任务(如 Celery 或者 MQ 等),执行长耗时任务,Django 会为该任务的函数第一次调用 ORM 时分配一条数据库连接,而且这个连接在 ORM 调用结束时不会立即释放,当你在同一个任务(长耗时)里其他地方再次调用 ORM 时,就会出现"MySQL server has gone away"的报错(原因是 MySQL 主动断开的)

    官方推荐解决方案: 如果在 Django 的请求-响应周期之外的长运行进程中创建了连接,该连接将保持打开状态,直到显式关闭或超时发生。你可以使用 django.db.close_old_connections() 来关闭所有旧的或不可用的连接。

    我觉得太 low 了。理论上,只需要设置每次调用 ORM 开始前获取一条连接,调用结束后关闭连接即可解决这个问题。

    有没有大佬遇到过这个问题?如何更加优雅的解决?

    10 条回复    2025-08-04 20:55:26 +08:00
    encro
        1
    encro  
       122 天前
    首先,
    你想知道 why“MySQL server has gone away”,
    然后才能对症下药。。。

    你可以试试问问 gpt 看看 MySQL server has gone away 的原因会有哪些,然后一个一个排除。
    zhaojiejoe
        2
    zhaojiejoe  
       122 天前
    确实需要调用 close_old_connections ,可以借鉴一下 huey 里面的写法 https://github.com/coleifer/huey/blob/master/huey/contrib/djhuey/__init__.py#L129
    a663
        3
    a663  
    OP
       121 天前
    @encro #1 审题。 原因已知,但是官方给的解决方案不优雅
    a663
        4
    a663  
    OP
       121 天前
    @zhaojiejoe #2 谢谢,加 wrapper 这个思路也是我们当前的方案,但是我们的整个 task 太复杂,很多个操作 ORM 的函数,导致我们需要在每一个函数上 wrapper ,目前这个也不是我们想要的。
    sthwrong
        5
    sthwrong  
       121 天前
    没用过 py 的 orm ,不过有个疑问,通常连接池都有个 testOnBorrow 之类的配置吗?这种情况会不会取一个新的连接?
    jackleo120
        6
    jackleo120  
       121 天前
    python 的数据库管理都需要手动显式关闭连接的,包括 django 和 fastapi 。最好的办法就是 执行 orm 的时候才手动开启连接以及关闭连接。
    gsfish
        7
    gsfish  
       121 天前
    可以试试 Django 4.1 引入的 CONN_HEALTH_CHECKS ,官方的说法是:

    Setting CONN_HEALTH_CHECKS to True can be used to improve the robustness of connection reuse and prevent errors when a connection has been closed by the database server which is now ready to accept and serve new connections, e.g. after database server restart. The health check is performed only once per request and only if the database is being accessed during the handling of the request.
    mingli
        8
    mingli  
       121 天前 via iPhone
    dramatiq 使用了中间件的方式,可以参考一下
    https://github.com/Bogdanp/django_dramatiq/issues/19
    a663
        9
    a663  
    OP
       121 天前
    @gsfish #7 这个试过,在长耗时的场景下不行
    akaHenry
        10
    akaHenry  
       116 天前
    这个 mysql 报错, 是 django 老问题了. 7~8 年前, 就这样.

    django.db.close_old_connections() 就是当时的解决办法. 楼上 参考 huey 的装饰器做法, 也很常见.

    (印象中的老项目, 当时也是写了个装饰器, 到处挂, 很恶心)

    我最近的新项目, 直接切 PG 了. PG 直接支持 连接池参数, 就没再遇到类似问题.

    https://docs.djangoproject.com/en/5.2/ref/databases/#connection-pool

    如果是新项目, 建议直接切 pg 吧, mysql 现在比 pg 全方位落后, 没有继续使用的必要.

    如果是老项目, 你可以搜索试试几个 django db connection pool 的库, 有支持 mysql 的.


    https://github.com/altairbow/django-db-connection-pool


    我没验证过. 不保证有效. mysql 的很多问题, 在 pg 这里, 都不存在.

    我线上的新项目, pg 跑了大半年了, 很稳定, 日志很健康. 也没遇到啥运维的坑.
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1559 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 22ms UTC 16:22 PVG 00:22 LAX 08:22 JFK 11:22
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86