当工作人员在创建之后执行任务时,我一直在遇到奇怪的mysql问题。
我们使用django 1.3,芹菜3.1.17,djorm-ext-pool 0.5
我们以并发3开始芹菜过程。 到目前为止,我的观察是,当工作进程启动时,它们都会获得相同的mysql连接。我们记录db connection id如下所示。
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) // Press Back Icon
{
finish();
}
return super.onOptionsItemSelected(item);
}
当所有工作人员获得任务时,第一个工作成功执行,但另外两个工作人员发出奇怪的Mysql错误。它或者是“Mysql服务器消失”的错误,或者是Django抛出“DoesNotExist”错误的情况。显然,Django查询的对象确实存在。
发生此错误后,每个工作人员都会开始获取自己的数据库连接,之后我们就不会发现任何问题。
芹菜的默认行为是什么?它是否旨在共享相同的数据库连接。如果是这样,如何处理进程间通信? 理想情况下,我希望每个工作者都有不同的数据库连接。
我尝试了下面链接中提到的代码,但是没有用。 Celery Worker Database Connection Pooling
我们还修复了下面建议的芹菜代码。 https://github.com/celery/celery/issues/2453
对于那些提出问题的人,请让我知道downvote的原因。
答案 0 :(得分:2)
Celery以下面的命令启动
celery -A myproject worker --loglevel=debug --concurrency=3 -Q testqueue
myproject.py
作为主进程的一部分,在分配工作进程之前对mysql数据库进行了一些查询。
作为主进程中查询流的一部分,django ORM会创建一个sqlalchemy连接池(如果它尚不存在)。然后创建工作进程。
芹菜作为django fixups的一部分关闭了现有的连接。
def close_database(self, **kwargs):
if self._close_old_connections:
return self._close_old_connections() # Django 1.6
if not self.db_reuse_max:
return self._close_database()
if self._db_recycles >= self.db_reuse_max * 2:
self._db_recycles = 0
self._close_database()
self._db_recycles += 1
实际上可能发生的情况是,具有一个未使用的数据库连接的sqlalchemy池对象在分叉时被复制到3个工作进程。因此,3个不同的池有3个连接对象指向相同的连接文件描述符。
当被要求进行数据库连接时,工作人员在执行任务时,所有工作人员都从sqlalchemy池获取相同的未使用连接,因为当前未使用该连接。所有连接指向同一文件描述符的事实导致MySQL连接消失了。
之后创建的新连接都是新的,并且没有指向相同的套接字文件描述符。
解决方案:
在主要流程中添加
from django.db import connection
connection.cursor()
在任何导入完成之前。即在添加偶数djorm-ext-pool
模块之前。
这样,所有数据库查询都将使用池外的django创建的连接。当芹菜django fixup关闭连接时,连接实际上是关闭的,而不是回到炼金术池,在分叉时应对所有工人时,炼金池没有连接。在工人要求数据库连接之后,sqlalchemy返回一个新创建的连接。