Celery是什么
工作模式
使用场景
手册:http://docs.celeryproject.org
一. 环境安装
windows下安装包(4版本已经移除对windows的支持,所以只能使用低版本的)
pip install celery==3.1.25
pip install celery-with-redis
Linux直接默认安装最新版本
- celery的使用
参考测试1文件
1. 基本配置
1. 创建app
在__init__.py中创建
from celery import Celery
# 创建 Celery 实例
app = Celery(app名称)
# 通过 Celery 实例加载配置模块
app.config_from_object('当前文件夹.配置文件')
2. 任务的书写,看具体要实现的功能来书写
3. 配置文件的书写
BROKER_URL = "redis://localhost:6379/0" # 指定 Broker
CELERY_RESULT_BACKEND = "redis://localhost:6379/1" # 指定 Backend
CELERY_TIMEZONE = 'Asia/Shanghai' # 指定时区,默认是 UTC
BROKER_TRANSPORT_OPTIONS = {'visibility_timeout': 43200}
# CELERY_TIMEZONE='UTC'
CELERY_IMPORTS = ( # 指定导入的任务模块
'celery_app.task1',
'celery_app.task2'
)
2. 手动驱动任务
在app配置的文件夹的当前目录写一个执行文件client.py
例如:
from celery_app import task1
from celery_app import task2
task1.add.apply_async(args=[2, 8]) # 也可用 task1.add.delay(2, 8)
task2.multiply.apply_async(args=[3, 7]) # 也可用 task2.multiply.delay(3, 7)
print('hello world')
# countdown:指定多少秒后执行任务
task1.add.apply_async(args=(2, 23), countdown=5) # 5 秒后执行任务
task1.add.apply_async(args=[6, 7], expires=10) # 10 秒后过期
执行方式:
终端上先找到app文件夹目录运行:celery -A celery_app worker --loglevel=info
再执行client.py
3. bast定时任务驱动任务(可某个时间调度,也可以每多少秒)
1. 在配置文件上添加调度
from datetime import timedelta
from celery.schedules import crontab
# schedules
CELERYBEAT_SCHEDULE = {
'add-every-30-seconds': {
'task': 'celery_app.task1.add',
'schedule': timedelta(seconds=3), # 每 30 秒执行一次
'args': (5, 8) # 任务函数参数
},
'multiply-at-some-time': {
'task': 'celery_app.task2.multiply',
'schedule': crontab(hour=9, minute=50), # 每天早上 9 点 50 分执行一次
'args': (3, 7) # 任务函数参数
}
}
2. 终端运行方式:
celery beat -A app目录文件夹 -l INFO (celery beat -A celery_app -l INFO)
celery worker -A app目录文件夹 -l INFO (celery worker -A celery_app -l INFO)
"-B"参数告诉celery在启动worker时同时启动celery beat, 并使用统一进程, 以便执行定期
Direct Exchange
如其名,直接交换,也就是指定一个消息被那个队列接收, 这个消息被celerybeat定义个一个routing key,如果你发送给交换机并且那个队列绑定的bindingkey 那么就会直接转给这个队列
Topic Exchange
你设想一下这样的环境(我举例个小型的应该用场景): 你有三个队列和三个消息, A消息可能希望被X,Y处理,B消息你希望被,X,Z处理,C消息你希望被Y,Z处理.并且这个不是队列的不同而是消息希望被相关的队列都去执行,看一张图可能更好理解:
对,Topic可以根据同类的属性进程通配, 你只需要routing key有’.’分割:比如上图中的usa.news, usa.weather, europe.news, europe.weather
Fanout Exchange
先想一下广播的概念, 在设想你有某个任务,相当耗费时间,但是却要求很高的实时性,那么你可以需要多台服务器的多个workers一起工作,每个服务器负担其中的一部分,但是celerybeat只会生成一个任务,被某个worker取走就没了, 所以你需要让每个服务器的队列都要收到这个消息.这里很需要注意的是:你的fanout类型的消息在生成的时候为多份,每个队列一份,而不是一个消息发送给单一队列的次数
- Django中使用celery
参照django_celery的设置
Redis==2.10.6 celery=3.1.15
django-celery
- Install: pip install django-celery
- Worker: python manage.py celery worker -Q queue
- Beat: python manage.py celery beat
from celery import Celery, platforms
platforms.C_FORCE_ROOT = True #加上这一行
工程中创建celeryconfig.py
# coding=utf-8
import djcelery
from celery import platforms
platforms.C_FORCE_ROOT = True
djcelery.setup_loader()
CELERY_IMPORTS = {
'course.tasks'
}
BROKER_BACKEND = 'redis'
BROKER_URL = "redis://localhost:6379/0" # 指定 Broker
CELERY_RESULT_BACKEND = "redis://localhost:6379/1" # 指定 Backend
# 有些情况可以防止死锁
CELERYD_FORCE_EXECV = True
# 设置并发worker数量
CELERYD_CONCURRENCY = 2
# 允许重试
CELERY_ACKS_LATE = True
# 每个worker最多执行多少个任务被销毁,可以防止内存销毁
CELERYD_MAX_TASKS_PER_CHILD = 100
# 单个任务最大运行时间
CELERYD_TASK_TIME_LIMIT = 12 * 30
CELERY_DEFAULT_QUEUE = "work_queue" # 默认的队列,如果一个消息不符合其他的队列就会放在默认队列里面
CELERY_QUEUES = {
"beat_tasks": {
"exchange": "beat_tasks",
"exchange_type": "direct",
"binding_key": "beat_tasks"
},
"work_queue": {
"binding_key": "work_queue.#",
"exchange": "work_queue",
"exchange_type": "direct",
},
}
from datetime import timedelta
CELERYBEAT_SCHEDULE = {
'task1':{
'task': 'course-task',
'schedule': timedelta(seconds=5),
'options':{
'queue':'beat_tasks'
}
}
}
Settings.py
INSTALLED_APPS = (
'djcelery',
)
# Celery
from .celeryconfig import *
Views.py
from django.shortcuts import render
from course.tasks import CourseTask
from django.http import JsonResponse
# Create your views here.
def do(request):
print 'start'
CourseTask.apply_async(args=[2, 8], queue="import_task")
print 'end'
return JsonResponse({'result':'ok'})
App中创建tasks.py
# coding=utf-8
from celery.task import Task
import time
class CourseTask(Task):
name = 'course-task'
def run(self, *args, **kwargs):
print 'start course task'
time.sleep(4)
print 'args={}, kwargs={}'.format(args, kwargs)
print 'end course task'
- Celery监控工具flower
pip install flower==0.9
python manage.py celery flower
celery flower --address=0.0.0.0 --port=5555 --broker=xxx --basic_auth=imooc:imooc
- Supervisor部署celery
pip install supervisor
Start: supervisord -c supervisord.conf
Tool: supervisorctl (命令:status,update,stop)
复制 echo_supervisord_conf > supervisord.conf
[include]
files = *.ini
[supervisorctl]
serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL for a unix socket
serverurl=http://127.0.0.1:9001 ; use an http:// url to specify an inet socket
[inet_http_server] ; inet (TCP) server disabled by default
port=*:9001 ; ip_address:port specifier, *:port for all iface
username=root ; default is no username (open server)
password=12321hjz ; default is no password (open server)
supervisor_celery_work.ini
[program:celery_course]
command=python manage.py celery worker -l INFO
directory=/home/tarena/PycharmProjects/celery_course
# enviroment=PATH="/usr/lib/python2.7/dist-packages"
stdout_logfile=/home/tarena/PycharmProjects/celery_course/logs/celery_work.log
stderr_logfile=/home/tarena/PycharmProjects/celery_course/logs/celery_work_err.log
autostart=true
autorestart=true
startsecs=10
stopwatisecs=60
priority=998