django + celery进阶(一)

1,创建一个django工程,并创建一个示例app

目录结果如下:

django + celery进阶(一)_第1张图片
django rest framework.png

2,配置settings.py

INSTALLED_APPS部分:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'djcelery',
    'kombu.transport.django',
]

如果没有djcelery应用,可以通过pip install django-celery安装

celery配置部分:

BROKER_URL = 'amqp://guest@localhost//' # 使用RabbitMQ作为消息代理

CELERY_RESULT_BACKEND = 'redis://localhost:6379/0' # 把任务结果存在了Redis

CELERY_TASK_SERIALIZER = 'msgpack' # 任务序列化和反序列化使用msgpack方案

CELERY_RESULT_SERIALIZER = 'json' # 读取任务结果一般性能要求不高,所以使用了可读性更好的JSON

CELERY_TASK_RESULT_EXPIRES = 60 * 60 * 24 # 任务过期时间,不建议直接写86400,应该让这样的magic数字表述更明显

CELERY_ACCEPT_CONTENT = ['json', 'msgpack'] # 指定接受的内容类型
CELERY_ANNOTATIONS = {
    'django_celery_demo1.tasks.add': {'rate_limit': '10/m'}
}

3,在工程目录下创建celery.py

from __future__ import absolute_import
import os
from celery import Celery

# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_celery_demo1.settings')

from django.conf import settings  # noqa

app = Celery('django_celery_demo1')

# Using a string here means the worker will not have to
# pickle the object when using Windows.
app.config_from_object('django.conf:settings')
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)


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

该脚本自动检测工程下的app中的tasks任务。

4.在每个app中,需要使用的异步任务都可以放在该app目录下的tasks.py脚本中

tasks.py

from __future__ import absolute_import

from celery import shared_task

@shared_task
def add(x, y):
    return x + y

@shared_task 装饰器让你可以创建tasks而不必关联具体的app实例

5.启动celery

celery -A django_celery_demo1 worker -l info

6.问题总结

6.1 操作时遇到'DisabledBackend' object has no attribute '_get_task_meta_for'的错误,后来在工程目录下的__init__.py中加入

from __future__ import absolute_import, unicode_literals
from .celery import app as celery_app

解决了这个问题;
6.2,datetime.datetime.now()格式序列化的时候出错
TypeError: datetime.datetime(2017, 9, 27, 21, 46, 24, 862000) is not JSON serializable
解决方案:

def date_handler(obj):
    return obj.isoformat() if hasattr(obj, 'isoformat') else obj

print json.dumps(data, default=date_handler)

6.3 最常见的错误KeyError

Did you remember to import the module containing this task?
Or maybe you are using relative imports?
Please see http://bit.ly/gLye1c for more information.

The full contents of the message body was:
{'utc': True, 'chord': None, 'args': [], 'retries': 0, 'expires': None, 'task': 'apps.app1.tuan.tuantask1', 'callbacks': None, 'errbacks': None, 'timelimit': (None, None), 'taskset': None, 'kwargs': {}, 'eta': None, 'id': 'f2f92c1d-ac6d-4131-a029-123fbfc4ab48'} (220b)
Traceback (most recent call last):
  File "/Library/Python/2.7/site-packages/celery/worker/consumer.py", line 455, in on_task_received
    strategies[name](message, body,
KeyError: 'apps.app1.tuan.tuantask1'

根据错误描述可以知道,是celery在任务中存储的任务名,和我们发送的调用信息的名字存在出入。celery消费者找不到任务。具体的解决方案视情况而定,我在遇到这种问题的时候,使用的解决办法为:
在settings中增加CELERY_IMPORTS 设置

你可能感兴趣的:(django + celery进阶(一))