celery四:示例,在django中使用celery---由视图函数触发任务

项目结构:

myproj

  /myproj

    __init__.py

    celery.py

    settings.py

  /app01

    tasks.py

    views.py

  /app02

    tasks.py

    views.py

 

一.在django中发起celery任务

pip install django

pip install celery

1.在项目myproj/myproj中新建celery.py,配置celery app实例:

from __future__ import absolute_import
from __future__ import unicode_literals
from celery import Celery
import os

app = Celery("myproj")  # 项目名称
# 让django知道环境变量的位置;第二个参数,项目名称.settings
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myproj.settings")
# 配置celery查找配置的位置:到settings中,找"CELERY_"开头的配置
app.config_from_object("django.conf:settings", namespace="CELERY")
# 自动加载,自动查找所有已注册的app下的tasks.py文件中的任务
app.autodiscover_tasks()

 

2.在项目myproj下的__init_.py文件中,必须添加以下内容:

from __future__ import absolute_import

from .celery import app as celery_app

__all__ = ['celery_app']

 3.在settings中,配置celery的配置:这里配置redis,当然还可配置其它的选项。

在django中配置redis,使用

CELERY_BROKER_URL = "redis://:123456@192.168.10.11"
CELERY_RESULT_URL = "redis://:123456@192.168.10.11"

 

而不是原来的

broker="redis://:123456@192.168.10.11"
backend="redis://:123456@192.168.10.11"

 

4.在各app项目下的tasks.py中,写任务 

# app01/tasks.py
from __future__ import unicode_literals
from celery import shared_task

# 注意在djanog中,任务装饰器:不是使用app实例的task方法(@app.task),而是使用celery中的@shared_task装饰任务;
# @shared_task
@shared_task
def add(x, y):
    print 'running task add......'
    return x + y

@shared_task
def mul(x, y):
    return x * y

 

5.任务由谁调用:定时任务或视图函数调用,这里使用视图函数调用

配置url:

#myproj/urls.py
from django.conf.urls import url
from app01 import views

urlpatterns = [
    url(r'^call_celery_func/$', views.call_celery_func),       
]

 

视图函数:

# app01/views.py

from django.shortcuts import render
from app01 import tasks

def call_celery_func(request):
    # 调用任务仍然使用delay
    res = tasks.add.delay(5, 999)
    print("task.add--tasks_id:   ", res.task_id)
    return render(res.task_id)

 

 

 6.前端,使用ajax请求celery的视图函数。

如果视图函数只返回task_id,那么将立即返回;然后调用另外一个接口去获取执行任务的结果;这样就实现了异步django。

因为celery的执行流程:调用任务tasks.add.delay(3, 5) --->将会立即写入中间件redis数据库中,并立即返回任务id---->worker进程,会再跟中间件redis数据库交互,从中取出任务执行,这里是耗时操作。

我们只需要分两次调用,第一次调用一个接口立即得到任务id;然后再用另外一个接口去获取任务执行的结果,这个接口必须像tornado一样实现回调异步返回或协程异步返回;这就实现了异步返回。

 

二、在另一台linux服务器上,开启worker进程

如果worker进程,跟发起django任务请求的进程,在同一台服务器上,可以使用同一份代码;

如果worker进程,跟发起django任务请求的进程,则必须在两台服务器上,都要复制一份代码。

因为,worker进程中调用的任务的函数,要有查找函数代码的地方;

因为,在django发起任务请求的时侯,只是将任务的函数名称保存到redis中;worker执行端,需要在worker所在的服务器上,查找 此函数名对应的代码,才能执行此函数。发起任务和接收任务的连接,靠的是中间件redis数据库;一个是向redis存放数据,一个是向redis数据库取数据。

celery -A myproj worker -l info

 

三、获取任务执行的结果

任务执行的结果,保存在中间件redis数据库中,可以在redis数据库中查找到任务执行结果。

在代码中,获取任务执行结果:

直接使用在django中发起任务时,接收任务结果的res,调用res.get()方法,获取结果。

from celery.result import AsyncResult

res = AsyncResult(任务id)
while res.ready():
  time.sleep(0.1)
  res.get()

 

如果,我们使用第二段中的方法(下面的方法),不等待任务执行结束,立即返回任务id,那么得不到任务执行的结果

def call_celery_func(request):
    res = tasks.add.delay(5, 999)
    return render(res.task_id)

 

此时,只能根据任务id,去获取任务执行的结果,方法:

from celery.result import AsyncResult

res = AsyncResult(id="任务id")
while res.status == "SUCCESS":
  time.sleep(0.1)   res.get()

 

 

不管使用哪种方法获取任务的执行结果,都是从中间件redis数据库中,去获取。

 

posted on 2018-08-18 21:58  myworldworld  阅读(621)  评论(0)    收藏  举报

导航