Celery简要介绍

Celery是Python开发的分布式任务调度模块,是一个异步的任务队列基于分布式消息传递。Celery本身不含消息服务,它使用第三方消息服务来传递任务,目前,Celery支持的消息服务有RabbitMQ、Redis甚至是数据库,当然Redis应该是最佳选择。

使用Redis作为Broker时,再安装一个celery-with-redis。

 

celery(芹菜)是一个异步任务队列/基于分布式消息传递的作业队列。

它侧重于实时操作,但对调度支持也很好。

celery用于生产系统每天处理数以百万计的任务。

celery是用Python编写的,但该协议可以在任何语言实现。它也可以用其他语言通过webhooks实现。

目前已知有php/ruby/nodejs的实现

为什么用Celery?

异步

耗时久的事儿可以扔给 Worker处理,处理完可以触发子任务提醒

天然的并发能力(多进程/协程)!

非常方便添加 Worker来增强处理能力

Celery提供了Web方式的监控/报警,这样,我们就可以监控每个任务的情况了

出现错误可以自动处理/重试

角色介绍

Brokers: 提供队列服务,Celery支持的Brokers有:

RabbitMQ(推荐)

Redis

MongoDB

Beanstalk

CouchDB

SQLAlchemy(MySQL/PostgreSQL/Sqlite/Oracle)

Amazon SQS等

Worker: 真正干活的,实际运行任务的节点

开始 Celery 的第一步

选择Broker

在你正式开始使用 Celery之前,你需要选择、安装并运行一个 broker。

Broker 是一种负责接收、发送任务消息(task messages)的服务

你可以从以下几种 broker中选择一个:

RabbitMQ :[[http://www.rabbitmq.com/]]

功能完整、安全、饱经实践检验的 broker。如果对你而言,不丢失消息非常重要,RabbitMQ将是你最好的选择。

请查看 [[/技术分享/Celery/broker-installation]]以便获得更多关于 RabbitMQ安装和配置相关的信息。

 

Redis :[[http://redis.io/]]

也是一个功能完整的 broker,但电源故障或异常将导致数据丢失。

请查看 [[/技术分享/Celery/otherqueues-redis]]以便配置相关的信息。

数据库

不推荐使用数据库作为消息队列,但在非常小的应用中可以使用。Celery可以使用 SQLAlchemy和 DjangoORMS。请查看 [[/技术分享/Celery/otherqueues-sqlalchemy]]或 [[/技术分享/Celery/otherqueues-django]]。

更多其他选择

除了上面列出的以外,还有其他可以选择的传输实现,例如 CouchDB,Beanstalk, MongoDB, and SQS。请查阅 Kombu的文档以便获得更多信息。

创建一个简单“任务”(Task)

from celery import Celery

app = Celery(
    'myapp',
    broker='amqp://guest@localhost//',
    #broker='redis://localhost:6379/0',
    # ## add result backend here ifneeded.
   
backend='amqp',
)


@app.task
def add(x, y):
    return x + y

运行 worker 服务器


celery -A tasks worker --loglevel=info


执行任务(task)

 


>>> result = add.delay(4, 4)


这里是一些你可以如何处理结果的方法:


>>> result.ready() # 任务是否已经执行,如果已经执行完毕,返回值为 True。False
>>> result.result # 任务还没完成,尚无返回值。None
>>> result.get() # 等待,直到任务执行完毕并返回值。8
>>> result.result # 直接返回结果,不产生任何错误。8
>>> result.successful() # 任务是否成功执行,如果成功则返回值 True。True


 


CELERY_RESULT_BACKEND ="amqp"#: 我们希望结果最多保存 5 分钟。 #: 注意,这个特性需要 2.1.1 以上版本 RabbitMQ 才能支持。#: 如果你使用的是早期版本的 RabbitMQ,请注释下面这行。
CELERY_TASK_RESULT_EXPIRES =300
BROKER_URL = "amqp:''guest:guest@localhost :5672''" #连接 broker
CELERY_RESULT_BACKEND = "amqp" #用于存储元数据(metadata)和返回值(return values)的后端
CELERY_IMPORTS = ("tasks", ) #列出 worker 需要 import 的模块


 

使用Redis作为Broker时,再安装一个celery-with-redis。

开始编写tasks.py:


# tasks.py



import time



from celery import Celery



celery = Celery(
, broker=
)
@celery.task



defsendmail(mail):



print(
 % mail[
])
time.sleep(
)
print(
)


然后启动Celery处理任务:


celery -
 tasks worker --loglevel=info


上面的命令行实际上启动的是Worker,如果要放到后台运行,可以扔给supervisor。

如何发送任务?非常简单:


tasks 
 sendmail
sendmail.delay(dict(to=
))
<AsyncResult: 
a0a9262-
-
-
-b7bf0ea7483b>


可以看到,Celery的API设计真的非常简单。

然后,在Worker里就可以看到任务处理的消息:


[
-
-
:
:
,
: WARNING/MainProcess] celery
[
-
-
:
:
,
: INFO/MainProcess] consumer: Connected to redis://localhost:
/
[
-
-
:
:
,
: INFO/MainProcess] Got task 
 broker: tasks.sendmail[
a0a9262-
-
-
-b7bf0ea7483b]
[
-
-
:
:
,
: WARNING/PoolWorker-
] sending mail to celery
[
-
-
:
:
,
: WARNING/PoolWorker-
] mail sent.
[
-
-
:
:
,
: INFO/MainProcess] Task tasks.sendmail[
a0a9262-
-
-
-b7bf0ea7483b] succeeded 
s:


 

要使celery找到相应的tasks有四种方法

1 在项目的celery中写tasks。如在djproj/djproj/celery.py中直接定义task

2 使用autodiscover 但是tasks必须定义在app目录下的名字为tasks.py的文件中,如:apps/app1/tasks.py 否则找不到 ,会报KeyError错误。

3 如果不使用autodiscover,可以在项目的celery中 import 相应的module,相当于在项目的celery中写了相应的task,如在celery.py中 import apps.app2.mytasks 

4 在settings.py中设置CELERY_IMPORTS = ('apps.app2.mytasks',) 写到module级 

 

第一,假设用户正发起一个request, 并等待request完成后返回.在这一request后面的view功能中,我们可能需要执行一段花费很长时间的程序任务,这一时间可能远远大于用户能忍受的范围.当这一任务并不需要立刻执行时,我们便可以使用Celery在后台执行,而不影响用户浏览网页.当有任务需要访问远程服务器完成时,我们往往都无法确定需要花费的时间.

第二则是定期执行某些任务.比如每小时需要检查一下天气预报,然后将数据储存到数据库中.我们可以编写这一任务,然后让Celery每小时执行一次.这样我们的web应用便能获取最新的天气预报信息.