使用 eventlet 在 celery 任务中处理数据库问题
Threading database issues in celery tasks using eventlet
我在开发虚拟机下有一个项目'ubuntu/trusty'。
我将 virtualenv 与以下软件包一起使用:
celery 3.1.23
eventlet 0.18.4
django 1.8.15
mysqlclient 1.3.9
Python 版本为 3.4.3。
MySql 版本是 5.5.
我使用 supervisor 和 eventlet 作为 运行 一些服务和 celery[=] 的工人35=]任务在其中。这是supervisor配置的部分:
[program:celery-worker-default]
command=/home/vagrant/.virtualenvs/meridian/bin/python /vagrant/meridian/meridian/manage.py celery worker --loglevel=INFO -P eventlet -c 3 -Q default -E -n default.queue
directory=/vagrant/meridian/meridian
user=vagrant
autostart=true
autorestart=true
stdout_logfile=/var/log/supervisor/celery-worker-default-stdout.log
stderr_logfile=/var/log/supervisor/celery-worker-default-stderr.log
priority=999
stdout_logfile_maxbytes=10MB
stdout_logfile_backups=5
stderr_logfile_maxbytes=10MB
stderr_logfile_backups=5
当任务 运行ning 时,它们失败并显示以下堆栈跟踪:
Traceback (most recent call last):
File "/home/vagrant/.virtualenvs/meridian/lib/python3.4/site-packages/celery/app/trace.py", line 231, in trace_task
loader_task_init(uuid, task)
File "/home/vagrant/.virtualenvs/meridian/lib/python3.4/site-packages/djcelery/loaders.py", line 114, in on_task_init
self.close_database()
File "/home/vagrant/.virtualenvs/meridian/lib/python3.4/site-packages/djcelery/loaders.py", line 85, in close_database
return self._close_database()
File "/home/vagrant/.virtualenvs/meridian/lib/python3.4/site-packages/djcelery/loaders.py", line 76, in _close_database
close()
File "/home/vagrant/.virtualenvs/meridian/lib/python3.4/site-packages/django/db/__init__.py", line 64, in close_old_connections
conn.close_if_unusable_or_obsolete()
File "/home/vagrant/.virtualenvs/meridian/lib/python3.4/site-packages/django/db/backends/base/base.py", line 403, in close_if_unusable_or_obsolete
self.close()
File "/home/vagrant/.virtualenvs/meridian/lib/python3.4/site-packages/django/db/backends/base/base.py", line 191, in close
self.validate_thread_sharing()
File "/home/vagrant/.virtualenvs/meridian/lib/python3.4/site-packages/django/db/backends/base/base.py", line 421, in validate_thread_sharing
% (self.alias, self._thread_ident, thread.get_ident()))
django.db.utils.DatabaseError: DatabaseWrapper objects created in a thread can only be used in that same thread. The object with alias 'default' was created in thread id 140089123953704 and this is thread id 140088751748512.
任何包含数据库操作的任务都会失败。
我尝试在任务主体中使用 select_for_update() 和 with atomic():,但没有任何成功。
我也在网上搜索过这个问题,但没有找到解决办法。
有人知道如何解决这个问题吗?
为 Celery 找到类似 on_load
的挂钩,并将以下代码放在那里:
import eventlet
eventlet.monkey_patch(MySQLdb=True)
它必须在任何 Django 代码之前执行。
我找到了答案。问题是我曾经在 manage.py 管理脚本下使用 运行 芹菜:
[program:celery-worker-default]
command=/home/vagrant/.virtualenvs/meridian/bin/python /vagrant/meridian/meridian/manage.py celery worker --loglevel=INFO -P eventlet -c 3 -Q default -E -n default.queue
我用这种方式重写了那行:
[program:celery-worker-default]
command=bash -c "/vagrant/meridian/meridian/start_default_queue.sh"
这是start_default_queue.sh的内容:
source /usr/share/virtualenvwrapper/virtualenvwrapper.sh
source /home/vagrant/.virtualenvs/meridian/bin/activate
workon meridian
exec celery worker --loglevel=INFO -P eventlet -c 3 -Q default -E -n default.queue
我不知道为什么,但是 运行ning celery worker 直接解决了那个神秘的问题。
我刚刚 运行 遇到了同样的问题,并且能够通过添加
来解决它
numprocs = 1
我的 celery 服务的 supervisord 配置。在您的示例中,这可能如下所示:
[program:celery-worker-default]
command=/home/vagrant/.virtualenvs/meridian/bin/python /vagrant/meridian/meridian/manage.py celery worker --loglevel=INFO -P eventlet -c 3 -Q default -E -n default.queue
directory=/vagrant/meridian/meridian
numprocs = 1
…
我不太清楚为什么这会改变任何东西,因为值 1 也应该是默认值。
我在开发虚拟机下有一个项目'ubuntu/trusty'。 我将 virtualenv 与以下软件包一起使用:
celery 3.1.23
eventlet 0.18.4
django 1.8.15
mysqlclient 1.3.9
Python 版本为 3.4.3。 MySql 版本是 5.5.
我使用 supervisor 和 eventlet 作为 运行 一些服务和 celery[=] 的工人35=]任务在其中。这是supervisor配置的部分:
[program:celery-worker-default]
command=/home/vagrant/.virtualenvs/meridian/bin/python /vagrant/meridian/meridian/manage.py celery worker --loglevel=INFO -P eventlet -c 3 -Q default -E -n default.queue
directory=/vagrant/meridian/meridian
user=vagrant
autostart=true
autorestart=true
stdout_logfile=/var/log/supervisor/celery-worker-default-stdout.log
stderr_logfile=/var/log/supervisor/celery-worker-default-stderr.log
priority=999
stdout_logfile_maxbytes=10MB
stdout_logfile_backups=5
stderr_logfile_maxbytes=10MB
stderr_logfile_backups=5
当任务 运行ning 时,它们失败并显示以下堆栈跟踪:
Traceback (most recent call last):
File "/home/vagrant/.virtualenvs/meridian/lib/python3.4/site-packages/celery/app/trace.py", line 231, in trace_task
loader_task_init(uuid, task)
File "/home/vagrant/.virtualenvs/meridian/lib/python3.4/site-packages/djcelery/loaders.py", line 114, in on_task_init
self.close_database()
File "/home/vagrant/.virtualenvs/meridian/lib/python3.4/site-packages/djcelery/loaders.py", line 85, in close_database
return self._close_database()
File "/home/vagrant/.virtualenvs/meridian/lib/python3.4/site-packages/djcelery/loaders.py", line 76, in _close_database
close()
File "/home/vagrant/.virtualenvs/meridian/lib/python3.4/site-packages/django/db/__init__.py", line 64, in close_old_connections
conn.close_if_unusable_or_obsolete()
File "/home/vagrant/.virtualenvs/meridian/lib/python3.4/site-packages/django/db/backends/base/base.py", line 403, in close_if_unusable_or_obsolete
self.close()
File "/home/vagrant/.virtualenvs/meridian/lib/python3.4/site-packages/django/db/backends/base/base.py", line 191, in close
self.validate_thread_sharing()
File "/home/vagrant/.virtualenvs/meridian/lib/python3.4/site-packages/django/db/backends/base/base.py", line 421, in validate_thread_sharing
% (self.alias, self._thread_ident, thread.get_ident()))
django.db.utils.DatabaseError: DatabaseWrapper objects created in a thread can only be used in that same thread. The object with alias 'default' was created in thread id 140089123953704 and this is thread id 140088751748512.
任何包含数据库操作的任务都会失败。
我尝试在任务主体中使用 select_for_update() 和 with atomic():,但没有任何成功。
我也在网上搜索过这个问题,但没有找到解决办法。
有人知道如何解决这个问题吗?
为 Celery 找到类似 on_load
的挂钩,并将以下代码放在那里:
import eventlet
eventlet.monkey_patch(MySQLdb=True)
它必须在任何 Django 代码之前执行。
我找到了答案。问题是我曾经在 manage.py 管理脚本下使用 运行 芹菜:
[program:celery-worker-default]
command=/home/vagrant/.virtualenvs/meridian/bin/python /vagrant/meridian/meridian/manage.py celery worker --loglevel=INFO -P eventlet -c 3 -Q default -E -n default.queue
我用这种方式重写了那行:
[program:celery-worker-default]
command=bash -c "/vagrant/meridian/meridian/start_default_queue.sh"
这是start_default_queue.sh的内容:
source /usr/share/virtualenvwrapper/virtualenvwrapper.sh
source /home/vagrant/.virtualenvs/meridian/bin/activate
workon meridian
exec celery worker --loglevel=INFO -P eventlet -c 3 -Q default -E -n default.queue
我不知道为什么,但是 运行ning celery worker 直接解决了那个神秘的问题。
我刚刚 运行 遇到了同样的问题,并且能够通过添加
来解决它numprocs = 1
我的 celery 服务的 supervisord 配置。在您的示例中,这可能如下所示:
[program:celery-worker-default]
command=/home/vagrant/.virtualenvs/meridian/bin/python /vagrant/meridian/meridian/manage.py celery worker --loglevel=INFO -P eventlet -c 3 -Q default -E -n default.queue
directory=/vagrant/meridian/meridian
numprocs = 1
…
我不太清楚为什么这会改变任何东西,因为值 1 也应该是默认值。