Django使用celery小记
基础环境
python 3.7
amqp 2.6.0
celery 4.4.3
Django 2.2
flower 0.9.4
可选使用djcelery,这里我使用的原生celery
celery简介及应用场景
Celery是基于Python开发的一个分布式任务队列框架,采用生产者-消费者模式,主要由三部分组成:broker(消息队列)、workers(消费者:处理任务)、backend(存储结果)
主要应用场景:
1、异步任务(async task) 针对请求执行的任务时间较长的情况
2、定时任务(crontab)
1.用户发起请求接口
2.接口将任务发送到broker队列
3.celery worker 监控 broker队列任务并处理
4.celery worker 将结果存储到backend
从图上可以看出Celery包含几个模块:
任务模块 Task (生产者)
包括异步任务和定时任务,异步任务通常在业务逻辑中被触发并发送到任务队列中,而定时任务是由Celery Beat进程周期性的将任务发往任务队列。
消息中间件 Broker (中间人)
Broker就是任务调度队列,接受任务生产者发送来的消息,将任务存入队列,之所以需要中间人的原因是Celrey本身是不提供消息队列的服务,所以需要第三方组件实现,常用的有RabbitMQ、Redis。
任务执行单元Worker (消费者)
Worker是执行任务的单元,它实时监控消息队列,如果有任务就获取任务并执行它。
任务存储Backend(存储结果)
Backend用于存储任务的执行结果,存储可以使用RabbitMQ或者Redis或者数据库等。
异步任务
目录结构
mysite/mysite是项目配置
mysite/ola_utils是新建的app
mysite
├── README.MD
├── db.sqlite3
├── manage.py
├── mysite
│ ├── __init__.py
│ ├── __pycache__
│ ├── celery.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── ola_utils
├── __init__.py
├── __pycache__
├── admin.py
├── apps.py
├── migrations
├── models.py
├── tasks.py
├── tests.py
└── views.py
celery主配置文件
'''
mysite/mysite/celery.py
'''
# -*- coding: utf-8 -*-
# @Time : 2020/6/8 5:03 PM
# @Author : zhangzd
# @Email : [email protected]
# @File : celery.py
# @Software: PyCharm
from __future__ import absolute_import, unicode_literals
import os
from celery import Celery, platforms
# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mysite.settings')
app = Celery('mysite', backend='amqp', broker='amqp://guest:guest@localhost:5672')
# 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()
# 允许root 用户运行celery
platforms.C_FORCE_ROOT = True
# 防止内存泄漏,限制worker执行任务次数
app.conf.worker_max_tasks_per_child = 40
@app.task(bind=True)
def debug_task(self):
print('Request: {0!r}'.format(self.request))
# 定时任务
from celery.schedules import crontab
app.conf.update(
CELERYBEAT_SCHEDULE={
'send-report': {
# 具体需要执行的函数
# 该函数必须要使用@shared_task装饰
'task': 'ola_utils.tasks.report',
# 定时时间
# 每分钟执行一次,不能为小数
'schedule': crontab(minute='*/1'),
# 或者这么写,每小时执行一次
# "schedule": crontab(minute=0, hour="*/1")
# 执行的函数需要的参数
'args': ()
}
}
)
在mysite/init.py文件中增加如下内容,确保django启动的时候这个app能够被加载到
'''
mysite/mysite/__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 import app as celery_app
__all__ = ('celery_app',)
注意tasks.py必须建在各app的根目录下,且只能叫tasks.py,不能随意命名
'''
mysite/ola_utils/tasks.py
'''
from __future__ import absolute_import, unicode_literals
from celery import shared_task
import time
@shared_task
def add(x, y):
time.sleep(10)
return x + y
在视图文件内调用视图函数触发异步任务
'''
mysite/ola_utils/views.py
'''
from django.shortcuts import render
# Create your views here.
import time
from django.http import HttpResponse
from ola_utils.tasks import add
def heartbeat(request):
t = time.time()
try:
# r = test.delay()
r = add.delay(2,6)
print(r)
except Exception as e:
print(e)
return HttpResponse(t)
启动celery worker
celery -A mysite worker -l info
定时任务
# 定时任务配置
from celery.schedules import crontab
app.conf.update(
CELERYBEAT_SCHEDULE={
'send-report': {
# 具体需要执行的函数
# 该函数必须要使用@shared_task装饰
'task': 'ola_utils.tasks.report',
# 定时时间
# 每分钟执行一次,不能为小数
'schedule': crontab(minute='*/1'),
# 或者这么写,每小时执行一次
# "schedule": crontab(minute=0, hour="*/1")
# 执行的函数需要的参数
'args': ()
}
}
)
'''
mysite/ola_utils/tasks.py
'''
@shared_task
def report():
print(5)
return 5
同时执行异步任务和定时任务
celery -B -A mysite worker -l info
结果
其他
celery 官网:https://docs.celeryproject.org/en/4.4.3/django/first-steps-with-django.html
celery 配置参数
https://docs.celeryproject.org/en/master/userguide/configuration.html?highlight=CELERYD_MAX_TASKS_PER_CHILD#std:setting-worker_max_tasks_per_child