Celery:是一个分布式队列的管理工具。
提供了简便的接口管理任务队列
生产者 user: 发布任务
任务队列 broker: 存储任务,常见的有redis,rabbitMQ
职程(工作者) worker: 处理任务
结果 backend 存储结果
首先需要一个redis服务器用来做消息队列和存储任务的结果,这个redis可以在本地,也可以在远程,他可能是一个redis服务,也可能是redis集群。
sudo apt-get install redis
vim /etc/redis/redis.conf
将保护模式关闭(protected mode: no), 注释掉(bind)。
cd /usr/bin/
./redis-server /etc/redis/redis.conf
需要一个被发布的任务
pip install celery
安装celery,注意版本可能与环境不切合,或者版本就是异常的,pip install --upgrade https://github.com/celery/celery/tarball/master,不是自己代码问题就把版本调低
pip install django-redis
redis支持
from celery import Celery
import time
app = Celery('tasks',broker='redis://ip:6379/0',backend='redis://ip:6379/1')
@app.task
def add(x,y):
time.sleep(10)
return x+y
# tasks.py
from somewhere import add
ret = add.delay(1,2)
# ret 就是一个id,可以凭借这个id去获取状态,如果是successful就可以获取结果信息。
celery worker -A folder.tasks -l info
# result.py 等执行完上个程序在执行这个
from celery.result import AsyncResult
from folder.tasks import app # 创建的Celery实例拿过来
# 上面的程序得到的ret是AsyncResult对象,调用.id方式得到他的id。
ret = AsyncResult(id =ret.id,app=app)
print(ret.state)
if ret.successful():
print(ret.get())
ret.state
:
PENDING: 等待
STARTED: 开始
SUCCESS: 成功
RETRY: 重试
FAILURE: 失败
REVOKED:取消
连接redis的时候:目标服务器拒绝访问?
将防火墙关闭,或者打开6379端口,使用windows命令telnet ip 6379
还是无法连接,将redis的配置文件中的pretected mode设置为no,将bind取消注释,或者绑定本机ip,然后重启redis,ps aux|grep redis
检查redis,如果是127.0.0.1:6379只能在本机使用,如果是 * :6379,或者本机ip:6379 成功,再试telnet ip 6379
,空白表示成功。
Celery出现语法错误?
Celery版本与Python版本的冲突,主要是async关键字,可以试着将它改为别的;或者安装低版本的:pip install --upgrade https://github.com/celery/celery/tarball/master
Celery任务一直在pending,不执行?
有几个任务已经存储(8)
,在redis没有数据的情况下,就简单的flushdb-Pthreads -c 6
效果更好-c指的是并发数,在这里是线程的个数
,还可以是’eventlet’ 、‘gevent’,大概率是win10版本的问题。celery_tasks
,创建一个celery.py文件用来创建celery配置文件,创建tasks01.py,tasks02.py用来定义不同类别的任务。from celery import Celery
app = Celery('task',broker='redis://ip:6379/0',backend='redis://ip:6379/1',
include('celery_tasks.tasks01','celery_tasks.tasks02')
# include 包含的是绝对路径
)
app.conf.timezone = 'Asia/Shanghai'
app.conf.enable_utc = False
# tasks01.py tasks02.py
from celery_tasks.celery import app
@app.task
def add(x,y):
return x+y
安装eventlet模块: pip install eventlet
运行celery:celery worker -A celery_tasks -l info -P eventlet
# ret.py
from celery.tasks.tasks01 import add
add.delay(1,5)
运行这个函数,celery收到了任务,但是没有执行,原因未知,还是之前的样子,使用多线程threads或者单进程solo就可以运行。可能跟系统有关系
1. 简单:
delay()在使用时更加的简单,将参数放里面就可以执行实时任务。
apply_async():有更多的参数:args=[] ,eta=国标时间
定时:
from datetime import datetime
from datetime import timedelta
v1 = datetime(2020, 3, 11, 16, 19, 00) # 2020年3月11日16点19分00秒
v2 = datetime.utcfromtimestamp(v1.timestamp()) # 转换为国标时间
ret = add.apply_async(args=[1,2],eta=v2)
延时:
from datetime import datetime
from datetime import timedelta
ntime = datetime.now()
utc_time = datatime.utcfromtimestamp(ntime.timestamp)
delta = timedelta(seconds = 6)
ret = add.apply_async(args=[1,2],eta=(dalta+utc_time))
2. 多任务:
# celery.py
from datetime import timedelta
from celery import Celery
from celery.schedules import crontab
app = Celery('tasks', broker='redis://ip:6379/1', backend='redis://ip:6379/2', include=[
'celery_tasks.task01',
'celery_tasks.task02',
])
app.conf.timezone = 'Asia/Shanghai'
app.conf.enable_utc = False
cel.conf.beat_schedule = {
# 名字随意命名,但是最好见名知意
'add-every-10-seconds': {
# 执行tasks1下的test_celery函数
'task': 'celery_tasks.task01.send_email',
# 'schedule': 1.0, # 和timedelta(seconds=1) 相同
'schedule': timedelta(seconds=6),
# 'schedule': crontab(minute="*/1"),
# 传递参数
'args': (1,2)
},
# 'add-every-12-seconds': {
# 'task': 'celery_tasks.task01.send_email',
# 每年4月11号,8点42分执行
# 'schedule': crontab(minute=42, hour=8, day_of_month=11, month_of_year=4),
# 'args': ('张三',)
# },
}
celery beat -A celery_tasks
:会读配置信息celery -A celery_tasks worker -l info
带来的问题:历史遗留
之前执行过这两条命令,然后停掉。
再次执行worker时,应该等待任务,但是却执行了很多任务
redis-cli可以用type查看
),首先创建一个python package my_celery
,下面有多个python package用来为任务分类,sms
package email
package,在任务包中必须有tasks.py文件用于定义任务,必须是tasks.py
,在最大的包 my_celery
中还有config.py
:Celery的配置信息。main.py
:创建celery对象,启动Django环境,扫描任务。
# config.py
broker = 'redis://ip:6379/0'
backend = 'redis://ip:6379/1'
# main.py
import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'celeryPros.settings.dev')
# import django
# # os.environ.setdefault('DJANGO_SETTINGS_MODULE','dailyfresh.settings')
# # django.setup()
from celery import Celery
app = Celery('demo')
-------------两种方式获取配置信息-----------------------
app.config_from_object("mycelery.config")
app.config_from_object('django.conf:settings')
app.autodiscover_tasks(['my_celery.sms',],related_name='tasks') # 默认就是tasks
# 里面是package的列表,默认扫描tasks,当指定related_name时,可以是其他名字
也可以扫描app中的任务,将app package加里面,如果有tasks.py就可以自动扫描
# tasks.py
from my_celery.main import app
@app.task
def add(x,y):
return x+y
消息中间件:因为网络抖动的原因放入多次数据,可以通过set保证幂等性,或者使用setnx命令保证幂等性,或者使用id保证唯一性。