Django中异步任务celery

Django中异步任务celery

本文主要讲述怎么在Django中应用Celery来完成异步任务.
最近公司在做支付宝接入的任务。主要是我们的系统和支付宝进行对接。也就是封装点API接口。在其中遇到一个问题,是这样的。支付宝的回调地址分为前台 同步回调后台异步回调,我们的系统必须在接到支付宝异步回调之后做些事情,但这些事情比较耗时,大概会花费2~3秒的样子,这对API接口的响应是无法接受的。后来想到了利用多线程来处理。但是Django貌似不支持多线程。即便是在一起请求过来后开启多线程去执行任务。照样会阻塞请求线程。最后经过Google 查到了 Celery的存在。下面来介绍下怎么应用在Django项目中。

一、什么是 Celery

官网描述如下:Celery是一个基于消息传递的异步任务队列。关注与时时操作,但是也支持任务调度。执行单元称之为Task,被一个或多个worker处理。该woker是使用multiprocessing, Eventlet, or gevent。Task能够被异步(后台)执行也可以被同步(等待完成)执行。Celery在生产服务器每天处理数以万计的Task。访问官网查看更多信息。

可见Celery主要是用来处理异步任务定时任务的。但我们为什么需要异步任务。或者定时任务呢?

1.1 假设用户发起一个request,并等待request返回。但是在request 经过django一层层处理到达我们的view时,view要进行一次比较耗时的操作,比如分析日志文件或者发起一个http请求。这些操作耗时无法确定,这样我们的API接口的响应时间就无法预知了。为了给用户以良好的体验,我们应该把这种耗时的任务放在后台处理。

1.2 定时任务,之前遇到一个需求是这样的。根据Django的日志数据分析用户的访问习惯和页面访问次数。这种任务不可能在用的时候再去分析统计,那肯定来不及了。所以需要在每天零点整自动分析这些日志。当遇到这种问题时我们可以采用Celery的定时任务。当然还有另一种解决方案,自定义Django Command 然后用shell脚本执行。然后添加到系统定时任(crontab)务里。

二、本文所依赖的库

Django (1.7.4)
Celery (3.1.17)
django-celery (3.1.16)

三、依赖库的安装

这里推荐vietualenv+virtualenvwarpper管理依赖环境,真心很方便

pip install django==1.7.4 
pip install celery==3.1.17
pip install django-celery==3.1.16

四、开始编码

django-admin.py startproject celery_tutorial
cd celery_tutorial/
django-admin.py startapp main

五、django设置

我们暂时使用django runserver来启动celery. 而Celery代理人(broker), 我们使用Django database broker implementation. 现在我们只需要知道Celery需要broker, 使用django自身便可以充当broker. (但在部署时, 我们最好使用更稳定和高效的broker, 例如Redis.)

在settings.py中:

import djcelery
djcelery.setup_loader()
BROKER_URL = 'django://'
...
INSTALLED_APPS = (
...
'djcelery',
'kombu.transport.django',
...
)

第一二项是必须的, 第三项则告诉Celery使用Django项目作为broker.

在INSTALLED_APPS中添加的djcelery是必须的. kombu.transport.django则是基于Django的broker

最后创建Celery所需的数据表, 运行:

python manage.py migrate

 六、配置View 以及 URL

新建并配置celery_tutorial/celery_tutorial/tasks.py

# encoding:utf-8
import time
from celery.task import task

@task
def _do_kground_work(name):
    """
    这里用time 模拟耗时操作
    """
    for i in range(1,10):
    print 'hello:%s %s'%(name,i)
    time.sleep(1)

配置celery_tutorial/celery_tutorial/views.py

# encoding:utf-8
from django.http import HttpResponse
from django.views.generic import View

from main.tasks import _do_kground_work

class Hello(View):

def get(self, request, *args, **kwargs):
    _do_kground_work.delay('GreenPine')
    return HttpResponse('Hello, World!')

配置celery_tutorial/celery_tutorial/urls.py:

from django.conf.urls import patterns, include, url
from django.contrib import admin
from main.views import Hello
urlpatterns = patterns('',
url(r'^$',Hello.as_view()),
url(r'^admin/', include(admin.site.urls)),
)

运行项目:

./manage.py runserver

七、测试

a、启动woker

正如之前说到的, 我们需要worker来执行task. 以下是在开发环境中的如何启动worker:

首先启动terminal, 如同开发django项目一样, 激活virtualenv, 切换到django项目目录. 然后启动django自带web服务器: python manage.py runserver.

python manage.py celery worker --loglevel=info

再生产环境中可以用如下命令启动woker,并用supervisor监控:

nohup python manage.py celery worker —loglevel=info&

b、测试task

在浏览器里输入http://localhost:8000/
此时请求会非常迅速,瞬间就返回了而不是等待_do_kground_work的执行。
如果你观察woker终端 你会发现有这样的输出:

[2015-02-11 16:13:25,490: INFO/MainProcess] Received task: main.tasks._do_kground_work[001a4d4b-4d9e-4a70-b2b4-876aca30a010]
[2015-02-11 16:13:25,493: WARNING/Worker-1] hello:GreenPine 1
[2015-02-11 16:13:26,494: WARNING/Worker-1] hello:GreenPine 2
[2015-02-11 16:13:27,496: WARNING/Worker-1] hello:GreenPine 3
[2015-02-11 16:13:28,498: WARNING/Worker-1] hello:GreenPine 4
[2015-02-11 16:13:29,499: WARNING/Worker-1] hello:GreenPine 5
[2015-02-11 16:13:30,499: WARNING/Worker-1] hello:GreenPine 6
[2015-02-11 16:13:31,501: WARNING/Worker-1] hello:GreenPine 7
[2015-02-11 16:13:32,502: WARNING/Worker-1] hello:GreenPine 8
[2015-02-11 16:13:33,503: WARNING/Worker-1] hello:GreenPine 9
[2015-02-11 16:13:34,527: INFO/MainProcess] Task main.tasks._do_kground_work[001a4d4b-4d9e-4a70-b2b4-876aca30a010] succeeded in 9.034652657s: None

猜你喜欢

转载自blog.csdn.net/niekunhit/article/details/50338537