我正在尝试设置django + celery + redis + celery_beats,但它给了我麻烦。文档非常简单,但是当我运行django服务器,redis,芹菜和芹菜节拍时,没有任何内容被打印或记录(我的所有测试任务都会记录它的东西)。
这是我的文件夹结构:
- aenima
- aenima
- __init__.py
- celery.py
- criptoball
- tasks.py
celery.py看起来像这样:
from __future__ import absolute_import, unicode_literals
import os
from django.conf import settings
from celery import Celery
# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'aenima.settings')
app = Celery("criptoball")
app.conf.broker_url = 'redis://localhost:6379/0'
# Using a string here means the worker doesn't have to serialize
# the configuration object to child processes.
# - namespace='CELERY' means all celery-related configuration keys
# should have a `CELERY_` prefix.
app.config_from_object('django.conf:settings', namespace='CELERY')
# Load task modules from all registered Django app configs.
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
app.conf.timezone = 'UTC'
@app.task(bind=True)
def debug_task(self):
print('Request: {0!r}'.format(self.request))
app.conf.beat_schedule = {
'test-every-30-seconds': {
'task': 'tasks.test_celery',
'schedule': 30.0,
'args': (16, 16)
}, }
和tasks.py看起来像这样:
from __future__ import absolute_import, unicode_literals
from datetime import datetime, timedelta
from celery import shared_task
import logging
from django_celery_beat.models import PeriodicTask, IntervalSchedule
cada_10_seg = IntervalSchedule.objects.create(every=10, period=IntervalSchedule.SECONDS)
test_celery_periodic = PeriodicTask.objects.create(interval=cada_10_seg, name='test_celery', task='criptoball.tasks.test_celery',
expires=datetime.utcnow()+timedelta(seconds=30))
@shared_task
def test_celery(x, y):
logger = logging.getLogger("AENIMA")
print("EUREKA")
logger.debug("EUREKA")
不确定我错过了什么。我跑的时候
celery -A aenima beat -l debug --scheduler django_celery_beat.schedulers:DatabaseScheduler
celery -A aenima worker -l debug
redis-cli ping PONG
django runserver和redis服务器,我什么都没打印。
settings.py
CELERY_BROKER_URL = 'redis://localhost:6379'
CELERY_RESULT_BACKEND = 'redis://localhost:6379'
CELERY_ACCEPT_CONTENT = ['application/json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_TIMEZONE = TIME_ZONE
CELERY_IMPORTS = ('criptoball.tasks',)
到目前为止,还没有在SO中找到任何关于此主题的声明答案。
我想解决所有问题,这个错误可能只是其中之一。非常感谢你的帮助!
修改
添加了redis的设置,以不同方式声明了任务并提高了调试级别。现在错误是:
收到类型为u'tasks.test_celery'的未注册任务。消息 被忽略并丢弃。
您记得导入包含此任务的模块吗?或者可能 你使用相对进口? KeyError:u'aenima.criptoball.tasks.test_celery'
我相信Celery的文档很差。
编辑2 在尝试了所有内容之后,当我将所有任务放在同一个celery.py文件中时,它就可以工作了。 @shared_task不起作用,不得不使用@ app.task。
答案 0 :(得分:9)
我以前遇到过这些问题。这不是你的代码。这通常是环境问题。
您应该在virtualenv
下运行所有内容,并使用特定软件包版本添加requirements.txt
文件。
关于celery 4.x
和django 1.x
存在一个已知问题,因此您应该考虑使用的软件包。
This教程将详细解释如何使用芹菜构建virtualenv
。
如果你能告诉我你的软件包版本,我可能会尝试以不同的方式提供帮助。
修改强>
我认为这与你经营芹菜的方式有关。如果我们解决了第一个问题,请尝试使用:
celery -A aenima.celery:app beat -l debug --scheduler django_celery_beat.schedulers:DatabaseScheduler
或
celery -A aenima.aenima.celery:app beat -l debug --scheduler django_celery_beat.schedulers:DatabaseScheduler
您获得的最新错误与模块发现有关。 先试试吧。
答案 1 :(得分:4)
使用virtualenv
可以很方便。
首先,像@Gal说你需要确保你有celery 4.x
。
您可以通过pip
:
pip install celery
当然,您也可以安装4.x
版本,将其添加到requirements.txt
中,如下所示:
芹菜== 4.1.0
或更高版本(如果将来可用)。
然后您可以使用以下方法重新安装所有包:
pip install -r requirements.txt
这将确保您安装了某些芹菜包。
现在Celery部分,虽然你的代码可能没有错,但我会写一些我如何让我的Celery应用程序工作的方式。
__ init __。py:
from __future__ import absolute_import, unicode_literals
# This will make sure the app is always imported when
# Django starts so that shared_task will use this app.
from .celery_conf import app as celery_app
__all__ = ['celery_app']
celery_conf.py:
from __future__ import absolute_import, unicode_literals
import os
from celery import Celery
from datetime import timedelta
# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', '<PATH.TO.YOUR.SETTINGS>')
app = Celery('tasks')
# Using a string here means the worker doesn't have to serialize
# the configuration object to child processes.
# - namespace='CELERY' means all celery-related configuration keys
# should have a `CELERY_` prefix.
app.config_from_object('django.conf:settings', namespace='CELERY')
# Load task modules from all registered Django app configs.
app.autodiscover_tasks()
# Set a beat schedule to update every hour.
app.conf.beat_schedule = {
'update-every-hour': {
'task': 'tasks.update',
'schedule': timedelta(minutes=60),
'args': (16, 16),
},
}
# The default task that Celery runs.
@app.task(bind=True)
def debug_task(self):
print('Request: {0!r}'.format(self.request))
tasks.py:
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import requests
from django.conf import settings
from django.http import HttpResponse
from celery.task import Task
from celery.five import python_2_unicode_compatible
from celery import Celery
app = Celery()
@python_2_unicode_compatible
class Update(Task):
name = 'tasks.update'
def run(self, *args, **kwargs):
# Run the task you want to do.
""" For me the regular TaskRegistry didn't work to register classes,
so I found this handy TaskRegistry demo and made use of it to
register tasks as classes."""
class TaskRegistry(Task):
def NotRegistered_str(self):
self.assertTrue(repr(TaskRegistry.NotRegistered('tasks.add')))
def assertRegisterUnregisterCls(self, r, task):
with self.assertRaises(r.NotRegistered):
r.unregister(task)
r.register(task)
self.assertIn(task.name, r)
def assertRegisterUnregisterFunc(self, r, task, task_name):
with self.assertRaises(r.NotRegistered):
r.unregister(task_name)
r.register(task, task_name)
self.assertIn(task_name, r)
def task_registry(self):
r = TaskRegistry()
self.assertIsInstance(r, dict, 'TaskRegistry is mapping')
self.assertRegisterUnregisterCls(r, Update)
r.register(Update)
r.unregister(Update.name)
self.assertNotIn(Update, r)
r.register(Update)
tasks = dict(r)
self.assertIsInstance(
tasks.get(Update.name), Update)
self.assertIsInstance(
r[Update.name], Update)
r.unregister(Update)
self.assertNotIn(Update.name, r)
self.assertTrue(Update().run())
def compat(self):
r = TaskRegistry()
r.regular()
r.periodic()
正如我在代码中所解释的那样,常规taskregistry
不适用于Celery 4.x中构建的那些,所以我使用了demo taskregistry。
你当然也可以不使用类来创建任务,但我更喜欢使用类。
settings.py:
# Broker settings for redis
CELERY_BROKER_HOST = '<YOUR_HOST>'
CELERY_BROKER_PORT = 6379
CELERY_BROKER_URL = 'redis://'
CELERY_DEFAULT_QUEUE = 'default'
# Celery routes
CELERY_IMPORTS = (
'PATH.TO.tasks' # The path to your tasks.py
)
CELERY_DATABASE_URL = {
'default': '<CELERY_DATABASE>', # You can also use your already being used database here
}
INSTALLED_APPS = [
...
'PATH.TO.TASKS' # But exclude the tasks.py from this path
]
LOGGING = {
...
'loggers': {
'celery': {
'level': 'DEBUG',
'handlers': ['console'],
'propagate': True,
},
}
}
我使用以下命令启动我的worker:
redis-server --daemonize yes
celery multi start worker -A PATH.TO.TASKS -l info --beat#但从路径中排除tasks.py
我希望这些信息可以帮助您或任何与Celery斗争的人。
编辑:
请注意,我将worker作为守护进程启动,因此您实际上无法在控制台中看到日志。
对我而言,它已记录在.txt
文件中。
另外请注意使用的路径,例如某些您需要包含应用路径的路径,如下所示:
project.apps.app
对于其他情况,您需要包含不带.py
的tasks.py,我写下了何时排除此文件以及何时不要。
编辑2:
@shared_task装饰器返回一个始终使用current_app中的任务实例的代理。 这使得@shared_task装饰器对库和可重用应用程序很有用,因为它们无法访问用户的应用程序。
请注意@shared_task
无法访问用户的应用。
您当前尝试注册的应用无法访问您的应用。
您实际要用于注册任务的方法是:
from celery import Celery
app = Celery()
@app.task
def test_celery(x, y):
logger = logging.getLogger("AENIMA")
print("EUREKA")
logger.debug("EUREKA")
答案 2 :(得分:3)
收到类型为u'tasks.test_celery'的未注册任务。该消息已被忽略并被丢弃。
您记得导入包含此任务的模块吗?或者你可能正在使用相对进口?
也许你的任务路径不正确,应该是:
app.conf.beat_schedule = {
'test-every-30-seconds': {
'task': 'criptoball.tasks.test_celery',
'schedule': 30.0,
'args': (16, 16)
},
}
tasks.test_celery
应为完整路径:criptoball.tasks.test_celery
答案 3 :(得分:2)
你应该修理一件事,使用:
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
告诉Celery如果您使用Celery 3.x,您希望它发现哪些应用程序的任务。