目录
目录树
DjangoProject
│── celery_handle
│ ├── config.py
│ ├── __init__.py
│ ├── manage.py
│ └── tasks.py
celery原理图
创建Celery
配置Celery参数
在创建celery实例之前,需要对celery的参数进行一些配置。
在这里列出一些比较常用的Celery配置项:
配置项名称 | 说明 |
---|---|
CELERY_DEFAULT_QUEUE | 默认的队列名称,当没有为task特别指定队列时,采用此队列 |
CELERY_BROKER_URL | 消息代理,用于发布者传递消息给消费者,推荐RabbitMQ |
CELERY_RESULT_BACKEND | 后端,用于存储任务执行结果,推荐redis |
CELERY_TASK_SERIALIZER | 任务的序列化方式(加密解密) |
CELERY_RESULT_SERIALIZER | 任务执行结果的序列化方式(加密解密) |
CELERY_ACCEPT_CONTENT | |
CELERYD_CONCURRENCY | 任务消费者的并发数 |
CELERY_TIMEZONE | 时区设置,计划任务需要,推荐 Asia/Shanghai |
CELERY_QUEUES | Celery队列设定,为任务指定不同队列 |
CELERY_ROUTES | Celery路由设定,用于给不同的任务指派不同的队列 |
CELERYBEAT_SCHEDULE | Celery计划任务设定 |
创建config.py配置文件
from kombu import Queue
#CELERY_BROKER_URL = 'redis://127.0.0.1:6379/8' # 中间件 地址
CELERY_RESULT_BACKEND = 'redis://127.0.0.1:6379/9' # 结果存放地址
#CELERY_TASK_SERIALIZER = 'msgpack' # 任务序列化和反序列化使用msgpack方案
#CELERY_RESULT_SERIALIZER = 'json' # 读取任务结果一般性能要求不高,所以使用了可读性更好的JSON
CELERY_TASK_RESULT_EXPIRES = 1200 # celery任务执行结果的超时时间,我的任务都不需要返回结果,只需要正确执行就行
CELERYD_CONCURRENCY = 50 # celery worker的并发数 也是命令行-c指定的数目
CELERYD_PREFETCH_MULTIPLIER = 4 # celery worker 每次去取任务的数量
CELERYD_MAX_TASKS_PER_CHILD = 40 # 每个worker执行了多少任务就会死掉
# CELERY_DEFAULT_QUEUE = "default_queue" # 默认的队列,如果一个消息不符合其他的队列就会放在默认队列里面
# 任务导入
# 这样Celery在启动时,会自动找到这些模块,并导入模块内的task
CELERY_IMPORTS = (
'celery_handle.tasks',
)
# 为Celery设定多个队列
# 创建Queue的实例时,传入name和routing_key,name即队列名称
CELERY_QUEUES = (
Queue(name='email_queue', routing_key='email_router'),
)
# 为不同的task指派不同的队列(路由)
# 那么task名称就是tasks.send_register_active_email
# 每个task的value值也是为dict,设定需要指派的队列name,及对应的routing_key
# 这里的name和routing_key需要和CELERY_QUEUES设定的完全一致
CELERY_ROUTES = {
# '任务函数': {'queue': '队列', 'routing_key': 'key'},
'celery_handle.tasks.send_register_active_email': {
'queue': 'email_queue',
'routing_key': 'email_router',
},
}
# 设定 Celery 时区
CELERY_TIMEZONE = 'Asia/Shanghai'
# CELERYBEAT_SCHEDULE # Celery计划任务设定 后面有描述
创建celery实例
将之前创建的config传递给app,用于载入celery实例。
manage.py
from celery import Celery
from celery_handle import config
CELERY_BROKER_URL = 'redis://127.0.0.1:6379/8' # 中间件 地址
# 创建一个Celery类的实例对象
app = Celery('celery_tasks.tasks', broker=config.CELERY_BROKER_URL)
# 载入celery配置
app.config_from_object(config)
创建异步任务
在项目的tasks下,定义一些异步任务函数。
对于需要在celery中异步执行的函数,只需要在函数上增加一个装饰器。
创建tasks.py
from __future__ import absolute_import
from celery_handle.manage import app
from django_redis import get_redis_connection
from django.conf import settings
from django.core.mail import send_mail
# 在worker端加这几句
import os
import django
# 为celery设置环境变量, 载入Django项目,才能调用该项目的模块
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "项目名.settings")
django.setup()
# 下面调用Django项目模块
import utils
# 定义任务函数 # name可以在这里指定队列
# @app.task(name="send_email")
@app.task()
def send_register_active_email(to_email, username, token):
'''发送激活邮件'''
subject = ''
message = ''
sender = settings.EMAIL_FROM
receiver = [to_email]
html_message = ''
send_mail(subject, message, sender, receiver, html_message=html_message)
异步执行任务
对于以app.task()装饰的函数,可以同步运行,也可以异步运行。
接上一个例子的send_register_active_email函数。
同步执行时,直接调用这个函数即可。
from celery_handle.tasks import send_register_active_email
send_register_active_email(to_email, username, token)
需要异步执行时,调用函数的delay()方法执行,此时会将任务委托给celery后台的worker执行。
from celery_handle.tasks import send_register_active_email
send_register_active_email.delay(to_email, username, token)
计划任务
celery除用于异步执行任务外,还可以用于执行计划任务。
设定celery时区
在开始配置计划任务之前对配置文件中设定celery时区。
# 设定 Celery 时区
CELERY_TIMEZONE = 'Asia/Shanghai'
定义计划任务
在配置文件中定义计划任务
计划任务也是异步执行任务的一种方式,为计划任务分配不同的队列。
在配置文件中,新增一项CELERYBEAT_SCHEDULE的配置
from datetime import timedelta
from celery.schedules import crontab
CELERYBEAT_SCHEDULE = {
# 计划任务名(自取)
'function_name': {
# task就是需要执行计划任务的函数
'task': 'celery_handle.tasks.function', # 函数位置
# 配置计划任务的执行时间,这里是每30秒执行一次
'schedule': timedelta(seconds=30),
# 传入给计划任务函数的参数
'args': {'value': '2333333'}
}
}
task即需要执行计划任务的函数
args是传递给计划任务函数的参数。如果无需参数,则args配置为None。
schedule即配置计划任务的执行时间,例子中使用的是timedelta实例,用于实现固定间隔某些时间执行。除此之外,还可以设定某个时间点执行,或重复某个时间点执行。这个就需要用到celery的crontab类。
'push_occupancy_rates': {
'task': 'handlers.schedules.test_func_b',
# 每天中午12点执行
'schedule': crontab(hour='12', minute='0'),
'args': None
},
关于crontab更详细的配置方式,可以参考官方手册:
Example | Meaning |
---|---|
crontab() | Execute every minute. |
crontab(minute=0, hour=0) | Execute daily at midnight. |
crontab(minute=0, hour='*/3') | Execute every three hours: midnight, 3am, 6am, 9am, noon, 3pm, 6pm, 9pm. |
crontab(minute=0, hour='0,3,6,9,12,15,18,21') | Same as previous. |
crontab(minute='*/15') | Execute every 15 minutes. |
crontab(day_of_week='sunday') | Execute every minute (!) at Sundays. |
crontab(minute='', hour='', day_of_week='sun') | Same as previous. |
crontab(minute='*/10', hour='3,17,22', day_of_week='thu,fri') | Execute every ten minutes, but only between 3-4 am, 5-6 pm, and 10-11 pm on Thursdays or Fridays. |
crontab(minute=0,hour='/2,/3') | Execute every even hour, and every hour divisible by three. This means: at every hour except: 1am, 5am, 7am, 11am, 1pm, 5pm, 7pm, 11pm |
crontab(minute=0, hour='*/5') | Execute hour divisible by 5. This means that it is triggered at 3pm, not 5pm (since 3pm equals the 24-hour clock value of “15”, which is divisible by 5). |
crontab(minute=0,hour='*/3,8-17') | Execute every hour divisible by 3, and every hour during office hours (8am-5pm). |
crontab(0, 0,day_of_month='2') | Execute on the second day of every month. |
crontab(0, 0, day_of_month='2-30/3') | Execute on every even numbered day. |
crontab(0, 0, day_of_month='1-7,15-21') | Execute on the first and third weeks of the month. |
crontab(0, 0,day_of_month='11', month_of_year='5') | Execute on the eleventh of May every year. |
crontab(0, 0, month_of_year='*/3') | Execute on the first month of every quarter. |
运行celery worker命令
celery -A celery_handle.manage worker -l info -f logs/celery.log
-A 创建实例的模块
-l 指定日志级别
-f 指定日志位置
指定消费的队列
在启动命令中,增加一个-Q的参数,用于指定消费的队列。
celery -A celery_handle.manage worker -l info -f logs/message.log -Q message_queue
上述的参数中,'-Q message_queue'两个参数,是指定这个worker名字为“message_queue”的队列。