官方文档: http://docs.celeryproject.org/en/latest/getting-started/first-steps-with-celery.html
这里使用RabbitMQ作为broker Redis作为backend
pip install celery
RabbitMQ用Erlang语言开发
下载epel仓库
yum install epel-release
安装erlang
yum install erlang
安装rabbitmq-server
yum install rabbitmq-server
启用管理界面插件
rabbitmq-plugins enable rabbitmq_management
启动
service rabbitmq-server start
管理界面端口为15672
添加用户相关命令
rabbitmqctl add_user
rabbitmqctl add_vhost
rabbitmqctl set_user_tags administrator
rabbitmqctl set_permissions -p ".*" ".*" ".*"
这里我们创建一个项目使用的用户(vanya)及Virtual Host (vanya)
rabbitmqctl add_user vanya 12345
rabbitmqctl add_vhost vanya
rabbitmqctl set_user_tags vanya administrator
rabbitmqctl set_permissions -p vanya vanya ".*" ".*" ".*"
登录后
安装
yum install redis
两种启动方式
service redis start
redis-server /etc/redis.conf
这里采用第二种方式,复制一个配置文件,并修改配置文件里的密码和端口
cp /etc/redis.conf /etc/redis6380.conf
vi /etc/redis6380.conf
端口改为6380(默认6379),添加密码(默认无密码,建议设置密码,空密码有漏洞)
后台启动
redis-server /etc/redis6380.conf &
其他命令
redis-cli -p 6380 # 连接redis
redis-cli -p 6380 shutdown # 关闭服务
新建simple_task.py
from celery import Celery
app = Celery('simple_task', broker='amqp://vanya:12345@localhost:5672/vanya',
backend='redis://:vanya@localhost:6380/0')
@app.task
def add(x, y):
print 'add', x, y
return x + y
创建一个Celery对象,消息中间件使用RabbitMQ,用户密码虚拟机是上面创建好的,接收任务结果backend使用的是redis。
通过使用装饰起@app.task定义一个任务add,执行简单的相加。
新建caller.py
from simple_task import add
add.delay(4, 5)
使用celery命令启动worker
celery -A simple_task worker -l info
运行报错
ImproperlyConfigured: You need to install the redis library in order to use the Redis result store backend.
忘记python的redis库,安装一下即可:
pip install redis
再次运行成功
使用-c参数可指定worker的并发数,不指定默认为4个
运行caller.py
python caller.py
调用后,worker窗口可看到输出如下:
这里调用端并未获取任务的结果
修改simple_task.py,添加time.sleep,模拟延长任务处理时间
@app.task
def add(x, y):
for i in range(10):
time.sleep(1)
print 'add', x, y
return x + y
修改caller.py
import time
from simple_task import add
result = add.delay(4, 5)
while not result.ready():
print 'not ready'
time.sleep(1)
print result.get()
重新启动worker,并调用caller,运行结果如下,可见多次获取状态为未准备好,最终任务结果返回为9:
修改task,使调用者可获取进度信息
修改simple_task.py,装饰器加入bind=True,则add函数传入第一个变量为Task自身,使用Task的update_state函数更新任务状态。state为自己命名的状态名称(系统内建的状态有PENDING,STARTED,SUCCESS,FAILURE,RETRY,REVOKED),meta为传入信息,可通过Task.info获取
@app.task(bind=True)
def add(self, x, y):
for i in range(10):
self.update_state(state='PROGRESS', meta={'current': i, 'total': 10})
time.sleep(1)
print 'add', x, y
return x + y
caller.py
result = add.delay(4, 5)
while not result.ready():
print 'not ready, state={0}'.format(result.state)
if result.state == 'PROGRESS':
print 'current={0}, total={1}'.format(result.info['current'], result.info['total'])
time.sleep(1)
print 'ready', result.state
print result.get()
调用者判断任务状态,如果状态为程序设置的PROGRESS,则可以通过info获取到设置的meta信息,caller.py运行结果: