分布式异步任务队列
利用的是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。协程数量不能太高,不然会出现大量的请求失败,导致没有数据