为啥 Celery 守护进程看不到任务?

Posted

技术标签:

【中文标题】为啥 Celery 守护进程看不到任务?【英文标题】:Why can't Celery daemon see tasks?为什么 Celery 守护进程看不到任务? 【发布时间】:2015-06-16 04:27:28 【问题描述】:

我有一个 Django 1.62 应用程序在 Debian 7.8 上运行,nginx 1.2.1 作为我的代理服务器,Gunicorn 19.1.1 作为我的应用程序服务器。我已经安装了 Celery 3.1.7 和 RabbitMQ 2.8.4 来处理异步任务。我可以将 Celery 工作者作为守护进程启动,但每当我尝试运行 Celery 文档中所示的测试“添加”任务时,都会出现以下错误:

Received unregistred task of type u'apps.photos.tasks.add'.
The message has been ignored and discarded.

Traceback (most recent call last):
File "/home/swing/venv/swing/local/lib/python2.7/site-packages/celery/worker/consumer.py", line 455, in on_task_received
strategies[name](message, body,
KeyError: u'apps.photos.tasks.add'

我所有的配置文件都保存在我的“myproj”项目目录下的“conf”目录中。 “添加”任务位于 apps/photos/tasks.py 中。

myproj
│
├── apps
    ├── photos
    │   ├── __init__.py
    │   ├── tasks.py
    conf
    ├── celeryconfig.py
    ├── celeryconfig.pyc
    ├── celery.py
    ├── __init__.py
    ├── middleware.py
    ├── settings
    │   ├── base.py
    │   ├── dev.py
    │   ├── __init__.py
    │   ├── prod.py
    ├── urls.py
    ├── wsgi.py

这是任务文件:

# apps/photos/tasks.py
from __future__ import absolute_import
from conf.celery import app

@app.task
def add(x, y):
    return x + y

这是我的 Celery 应用程序和配置文件:

# conf/celery.py
from __future__ import absolute_import
import os
from celery import Celery
from django.conf import settings
from conf import celeryconfig

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'conf.settings')
app = Celery('conf')
app.config_from_object(celeryconfig)
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)

@app.task(bind=True)
def debug_task(self):
    print('Request: 0!r'.format(self.request))

# conf/celeryconfig.py
BROKER_URL = 'amqp://guest@localhost:5672//'
CELERY_RESULT_BACKEND = 'amqp'
CELERY_ACCEPT_CONTENT = ['json', ]
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'

这是我的 Celery 守护进程配置文件。我注释掉了 CELERY_APP,因为我发现如果我取消注释,Celery 守护程序甚至都不会启动。我还发现我需要向 CELERYD_OPTS 添加“--config”参数才能启动守护程序。我创建了一个可以写入日志和 pid 文件的非特权“芹菜”用户。

# /etc/default/celeryd
CELERYD_NODES="worker1"
CELERYD_LOG_LEVEL="DEBUG"
CELERY_BIN="/home/myproj/venv/myproj/bin/celery"
#CELERY_APP="conf"
CELERYD_CHDIR="/www/myproj/"
CELERYD_OPTS="--time-limit=300 --concurrency=8 --config=celeryconfig"
CELERYD_LOG_FILE="/var/log/celery/%N.log"
CELERYD_PID_FILE="/var/run/celery/%N.pid"
CELERYD_USER="celery"
CELERYD_GROUP="celery"
CELERY_CREATE_DIRS=1

我可以从日志文件中看到,当我运行命令“sudo service celeryd start”时,Celery 启动时没有任何错误。但是,如果我打开 Python shell 并运行以下命令,我会看到我在开头描述的错误。

$ python shell
In [] from apps.photos.tasks import add
In [] result = add.delay(2, 2)

有趣的是,如果我检查 Celery 注册的任务对象,会列出该任务:

In [] import celery
In [] celery.registry.tasks

Out [] 'celery.chain': ..., 'apps.photos.tasks.add': <@task: apps.photos.tasks.add of conf:0x16454d0> ...

这里的其他类似问题已经讨论过使用 PYTHONPATH 环境变量,而我没有这样的变量。我一直不明白如何设置 PYTHONPATH,而且这个项目在没有它的情况下已经运行了一年多。

我还应该补充一点,我的生产设置文件是 conf/settings/prod.py。它从 base.py 导入我的所有基本(独立于层)设置,并添加一些额外的生产相关设置。

谁能告诉我我做错了什么?我已经为这个问题苦苦挣扎了三天了。

谢谢!

【问题讨论】:

使用这个:***.com/a/10236402/3982673 【参考方案1】:

看起来这是由于相对导入错误而发生的。

>>> from project.myapp.tasks import mytask
>>> mytask.name
'project.myapp.tasks.mytask'

>>> from myapp.tasks import mytask
>>> mytask.name
'myapp.tasks.mytask'

如果您使用相对导入,则应明确设置名称。

@task(name='proj.tasks.add')
def add(x, y):
   return x + y

结帐:http://celery.readthedocs.org/en/latest/userguide/tasks.html#automatic-naming-and-relative-imports

【讨论】:

我的 tasks.py 文件在 apps.photos.tasks 中,所以我将 add 方法的装饰器更改为 "@app.task(name='apps.photos.tasks.add') 但我仍然得到 KeyError。 如果您使用-l info 选项启动您的工作人员,您的任务名称会显示在开头吗? 不,我也试过了,发现没有任务显示。我已经开始构建一个测试 Django 应用程序,并且正在阅读 Celery 文档的页面,并尝试不同的方法来尝试了解我的配置中的问题所在。现在已经五天了。这是我在没有找到解决方案的情况下解决问题的时间最长的一次。 我现在想弄清楚的问题是 Initd celeryd 脚本如何知道项目中的哪个文件包含“app = Celery('tasks')”行?在我的测试 Django 项目中,这一行位于文件 myproj/conf/tasks.py 中(其中 myproj 是项目的根目录,而我的其他设置文件,如 settings.py、urls.py 和 wsgi.py 位于“conf”子目录。如果我的 celeryd 文件中没有 CELERY_APP,Celery 启动正常。celeryd 如何知道 Celery 应用程序的定义位置? @Robert 你是怎么“弄清楚”的?答案是什么。我知道这是旧的,但我们将不胜感激。【参考方案2】:

我正在使用 celery 4.0.2 和 django,我创建了一个 celery 用户和组以用于 celeryd,并且遇到了同样的问题。命令行版本运行良好,但 celeryd 没有注册任务。这不是一个相对命名问题。

解决方案是将 celery 用户添加到可以访问 django 项目的组中。就我而言,这个组是具有读取、执行和不写入功能的 www-data。

【讨论】:

以上是关于为啥 Celery 守护进程看不到任务?的主要内容,如果未能解决你的问题,请参考以下文章

celery: 守护进程不允许有子进程

celery 基础教程:守护进程

Django celery 和 celery-beat 守护进程脚本错误

celery django 守护进程上的多个工作人员和多个队列

Centos7 使用 Supervisor 守护进程 Celery

如何使用 Django 配置 Celery 守护进程