分布式异步任务队列

利用的是Celery+rabbitmq来实现

Celery
Celery是一种分布式的异步任务队列,让应用程序可能需要执行任何消耗资源的任务都交给任务队列,让应用程序能够自如快速地相应客户端地请求 任务队列 任务队列是一种被用来向线程或者机器分发任务的机制,一个任务队列输入的单元被称为一个task,专用的worker线程持续的监听任务队列等待新的任务出现去执行. Celery的通信通过消息来执行,通常使用一个broker来在客户端和worker之间作为中间件.初始化一个任务时,客户端发送一个message给任务队列,然后broker分发message向各个worker Celery需要一个消息缓存区发送和接受消息,RabbitMQ和Redis来作为broker,即消息的中间件 异步任务: 简而言之,做一个注册的功能,在用户使用邮箱注册成功之后,需要给该邮箱发送一封激活邮件。如果直接放在应用中,则调用发邮件的过程会遇到网络IO的阻塞,比好优雅的方式则是使用异步任务,应用在业务逻辑中触发一个异步任务。

安装golang和rabbitmq

windows:https://www.cnblogs.com/ericli-ericli/p/5902270.html

linux:https://blog.csdn.net/qq_22075041/article/details/78855708\

 

from __future__ import absolute_import, unicode_literals
import os
from celery import Celery
from celery.result import AsyncResult
from kombu import Queue, Exchange


# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ApiAutomation.settings')#配置django环境

# set message queue and tasks list
app = Celery('atp',                                              #创建Celery实例
             broker='pyamqp://guest:guest@localhost:5672//',     #发送消息到rabbitmq中
             backend='rpc://localhost',                             #结果存储(可以不填)
             include=['backend.case.execute.taskrun', 'backend.case.execute.caserun'])  #执行分布式的代码文件路径

# Using a string here means the worker will not have to
# pickle the object when using Windows.
app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks()

# Optional configuration, see the application user guide.
app.conf.update(                                                #配置Celery的基本配置:超时、任务序列化、内容格式、时间
    result_expires=60,
    task_serializer='json',
    accept_content=['json'],  # Ignore other content
    result_serializer='json',
    timezone='Asia/Shanghai',
    enable_utc=True,

    task_queues=(                                                            #创建消息队列,交换机名称、路由关键字,决定消息进到那个队列
        Queue('TEST', Exchange('run'), routing_key='run.TEST'),
        Queue('PRE_RELEASE', Exchange('run'), routing_key='run.PRE_RELEASE'),
        Queue('ONLINE', Exchange('run'), routing_key='run.ONLINE'),
        ),

    task_default_queue='celery',                                            #不设置的话,默认消息队列名称、交换机名称等信息    
    task_default_exchange='celery',
    task_default_exchange_type='direct',
    task_default_routing_key='celery',
    task_track_started=True,
)

@app.task
def error_handler(uuid):                                                    #错误回调机制
    result = AsyncResult(uuid)
    exc = result.get(propagate=False)
    print('ERROR:Task {0} raised exception: {1!r}\n{2!r}'.format(
        uuid, exc, result.traceback))

参数:https://www.jianshu.com/p/a505463ca840

2. 任务调用

任务(task)调用有三个API:

#给任务发送消息
apply_async(args[,kwargs[, ...]])

#给任务发送消息的简单版,但是不支持execution options(apply_async有三个部分的参数,第一部分就是task里面的python function的参数,比如add(x,y)的x,y,第二个参数叫作keyword arguments,就是设定一些环境变量,第三个参数就是execution options,也就是这个task本身的执行选项,时间啊之类)
delay(*args, **kwargs)

#类似直接调用的意思,即不是让worker来执行任务,而是当前的进程来执行。
calling(__call__)

Link(callbacks/errbacks)

就是一个任务接着一个,回调任务作为一个partial argument在父任务完成的时候被调用。

add.apply_async((2, 2), link=add.s(16))

allow_join_result:

对group得到的任务队列,allow_join_result来实现对执行完的结果一一对应

 

消息发布到队列后

消费者worker从队列中取消息到服务器中执行

重新开启终端输入:celery -A ApiAutomation.celeryapp:app worker -l info -n worker1@local --concurrency=2 -P gevent

 

-A指明app所在的模块, worker1@local表明当前机器的身份;-l是log的等级;-P是表明并发的方式,默认是单线程,这里使用的是协程;-c表示协程的数量,这里是2。协程数量不能太高,不然会出现大量的请求失败,导致没有数据

 

 

posted @ 2018-11-02 17:25  oneforall97  阅读(106)  评论(0编辑  收藏  举报