当 Django 结合异步任务(如 Celery 或者 MQ 等),执行长耗时任务,Django 会为该任务的函数第一次调用 ORM 时分配一条数据库连接,而且这个连接在 ORM 调用结束时不会立即释放,当你在同一个任务(长耗时)里其他地方再次调用 ORM 时,就会出现"MySQL server has gone away"的报错(原因是 MySQL 主动断开的)
官方推荐解决方案: 如果在 Django 的请求-响应周期之外的长运行进程中创建了连接,该连接将保持打开状态,直到显式关闭或超时发生。你可以使用 django.db.close_old_connections() 来关闭所有旧的或不可用的连接。
我觉得太 low 了。理论上,只需要设置每次调用 ORM 开始前获取一条连接,调用结束后关闭连接即可解决这个问题。
有没有大佬遇到过这个问题?如何更加优雅的解决?
![]() |
1
encro 2 天前
首先,
你想知道 why“MySQL server has gone away”, 然后才能对症下药。。。 你可以试试问问 gpt 看看 MySQL server has gone away 的原因会有哪些,然后一个一个排除。 |
![]() |
2
zhaojiejoe 2 天前
确实需要调用 close_old_connections ,可以借鉴一下 huey 里面的写法 https://github.com/coleifer/huey/blob/master/huey/contrib/djhuey/__init__.py#L129
|
4
a663 OP @zhaojiejoe #2 谢谢,加 wrapper 这个思路也是我们当前的方案,但是我们的整个 task 太复杂,很多个操作 ORM 的函数,导致我们需要在每一个函数上 wrapper ,目前这个也不是我们想要的。
|
5
sthwrong 2 天前
没用过 py 的 orm ,不过有个疑问,通常连接池都有个 testOnBorrow 之类的配置吗?这种情况会不会取一个新的连接?
|
6
jackleo120 2 天前
python 的数据库管理都需要手动显式关闭连接的,包括 django 和 fastapi 。最好的办法就是 执行 orm 的时候才手动开启连接以及关闭连接。
|
![]() |
7
gsfish 2 天前
可以试试 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. |
![]() |
8
mingli 1 天前 via iPhone
dramatiq 使用了中间件的方式,可以参考一下
https://github.com/Bogdanp/django_dramatiq/issues/19 |