项目是 django 使用 celery 做一些异步任务执行。
目前发现部署后,django view 中调用 celery 异步执行任务时,遇到一个诡异的问题
方法中的一条模型查询语句,在该异步方法被执行一定次数后会直接卡死。
例如 Person.objects.get(id=1)
执行到这一句后,后续语句就不会执行了。几十分钟后仍然不会执行。
也没有任何报错。
数据库表里面肯定有这条数据,而且只有一条数据。
使用 Person.objects.filter(id=1).first()的方式,也是同样的问题。
但是我改成直接用 django.db.connections 执行 sql 语句去查询结果,就没这个问题。
目前发现异步任务方法大概被执行一定数量范围后,就会触发卡死的问题。 而且在这个次数范围内必现。
当次执行卡死后,再次执行该异步任务,大概率就不会卡死了。
不知道有没有其他小伙伴遇到这么诡异的问题的,或者有没有原因的可能思路。
django 版本用的是 2.1.5
celery 版本是 4.4.2
感激不尽。
1
LemonK 2022-01-16 20:17:05 +08:00
mysql ?排查一下有没有其他线程共享同一个 DB 连接且事务未关闭。
|
2
piaochen0 OP @LemonK 是的,mysql 。
当时运行的场景其实是起了好多线程来执行同一个方法,所有的线程都会卡死在那一行。都没有使用事务。 后来使用单线程来跑,本来以为应该没问题了,但是跑着跑着,也出现了同样的问题。 当时也没有其他异步任务在执行。 |
3
darkengine 2022-01-16 21:07:47 +08:00 1
看下 mysql 日志是不是连接池满了
|
4
zachlhb 2022-01-17 08:13:04 +08:00 via iPhone
有没有用线程?用线程要在每个线程执行完手动关闭数据库连接,否则连接数会爆掉
|
5
kidblg 2022-01-17 09:41:14 +08:00
|
6
hscxrzs 2022-01-17 09:49:52 +08:00
如果有可以复现的最小代码集就好了
|
7
ibuler 2022-01-17 10:53:52 +08:00
@kidblg 的思路是对的,如果 celery 使用了线程模型,使用完数据库后应该手动关闭连接,这些动作如果在 view 中不用处理,django 自己操作的。
``` # from django.db import close_old_connections 点进去 # Register an event to reset transaction state and close connections past # their lifetime. def close_old_connections(**kwargs): for conn in connections.all(): conn.close_if_unusable_or_obsolete() signals.request_started.connect(close_old_connections) signals.request_finished.connect(close_old_connections) ``` 所以在 celery 中,用到的查询,都应该手动执行 close_old_connections ,如果是 celery 是 process 模型就不用处理了 |
8
ibuler 2022-01-17 11:04:11 +08:00
也可以通过信号机制来处理,任务执行前,执行后做同样的动作,这样可能更优雅,其他开发人员,不需要再去处理连接的事情
``` # ops/signal_handlers.py from django.db import close_old_connections from celery.signals import task_prerun, task_postrun @task_prerun.connect() def on_celery_task_pre_run(task_id='', **kwargs): # 关闭之前的数据库连接 close_old_connections() @task_postrun.connect() def on_celery_task_post_run(**kwargs): close_old_connections() # ops/apps.py app 中导入信号处理器 class OpsConfig(AppConfig): name = 'ops' def ready(self): from . import signal_handlers super().ready() ``` |
9
leven87 2022-01-18 14:58:44 +08:00
用 pgsql 想复现,但是没发现有问题
|