[django]celery_redis探索
celery用于异步处理耗时任务
celery特性
方便查看定时任务的执行情况, 如 是否成功, 当前状态, 执行任务花费的时间等.
使用功能齐备的管理后台或命令行添加,更新,删除任务.
方便把任务和配置管理相关联.
可选 多进程, Eventlet 和 Gevent 三种模型并发执行.
提供错误处理机制.
提供多种任务原语, 方便实现任务分组,拆分,和调用链.
支持多种消息代理和存储后端.
Celery 是语言无关的.它提供了python 等常见语言的接口支持.
脚本命令效果是, 执行命令,返回此次任务的id,任务放后台执行不用等待.
在web中效果是: 提交任务, 刷新页面, 任务正在执行中...
我们希望
获取任务执行状态
获取任务执行结果
暂停任务
终止(取消)(撤销)任务
- 耗时调用
用户注册(提高并发, 发邮件)
执行linux耗时脚本等
- 定时调用
到多久后执行
- 周期调用
celery组件
user: 用户通过执行脚本/页面点击投递任务到broker, 让woker处理
beats: 定时投递任务到broker, 让woker处理
broker: 消息队列, 支持redis or rabbitmq
worker: 处理耗时任务(干活的)
Backend: 结果存储 ,支持redis or rabbitmq or mongodb, mysql等
工作流: betats/用户投递任务->broker->worker->backend
注: 把mq里的信息称为: message
任务(函数+参数)提交 deplay/apply_sync执行了: 普通任务
任务(函数+参数)不想立刻执行, 先签名保存, 作为子任务被被任务编排画布调用: 称为 signature
测试耗时任务
- centos安装python3
- 安装celery
- 下面版本linux和windows兼容.
pip install redis==2.10.5
pip install celery==3.1.25
docker run -d -p 5672:5672 rabbitmq
docker run -d -p 6379:6379 redis
docker run -d -p 11211:11211 memcached
docker run -d -p 27017:27017 mongo
- 更新的版本(仅linux)
pip install -U "celery[redis]"
- 测试耗时/周期任务
参考
# tasks.py
from celery import Celery
from celery.schedules import crontab
import time
from celery.task import periodic_task
app = Celery('tasks', broker='redis://localhost:6379/0', backend="redis://localhost:6379/1", )
# 异步任务
@app.task
def send_mail(email):
print("send mail to ", email)
time.sleep(15)
return "[send_mail]: exec success"
# 定时任务(每分钟投递一次任务)
@periodic_task(run_every=crontab())
def some_task():
print('periodic task test!!!!!')
time.sleep(5)
print('success')
return "[periodic_task]some_task: exec succ!!"
# 用户投递任务到worker
耗时任务提交很快
不管worker是否在线,都可以随意提交任务
deplay函数是apply_async快捷方式
# user.py
from tasks import send_mail
def register():
import time
start = time.time()
print("1. 插入记录到数据库")
print("2. celery 帮我发邮件")
send_mail.delay("xx@gmail.com")
print("3. 告诉用户注册成功")
print("耗时:%s 秒 " % (time.time() - start))
if __name__ == '__main__':
register()
for i in `seq 1 20`;do python3 user.py;done
# beats周期投递任务到worker
celery -A tasks beat --loglevel=info
# 启动worker.
-A --app=APP Celery instance所在py文件名.
会将tasks.py @app.task装饰的任务全部加载
export C_FORCE_ROOT='true'
celery -A tasks worker --loglevel=info
# 可以看到积压的任务会陆续被worker执行
子任务和任务流
有时我们并不想简单的将任务发送到队列中,我们想将一个任务函数(由参数和执行选项组成)作为一个参数传递给另外一个函数中,
为了实现此目标,Celery使用一种叫做signatures的东西。
普通函数, 加括号, 带参数, 就执行了. 或提交给broker异步执行.
但有时需要将这些任务编排, 先把每个子任务 函数+参数保存起来(签名), 编排好后, 按照画布上的设计流程执行即可.
signature()包含了以下参数:
任务调用的 arguments(参数,即任务本身的参数,像add(x,y)中的参数)
keyword arguments(关键字参数,就是debug=false,true这类参数)
execution options(执行选项,比如运行时间countdown,到期时间expirt)。
# 创建任务函数
@celery_app.task
def my_task1(a, b):
print("任务函数(my_task1)正在执行....")
return a + b
# 创建签名并编排
from celery import group
from celery import signature
t1 = signature(my_task1,args=(1, 2),countdown=1)
my_group = group(t1,t2,t3)
//signature的快捷方式 .s
result = chain(add.s(2, 2), add.s(4), add.s(8))()
画布(canvas): 设计Celery的工作流(任务编排)
celery\canvas.py
官文参考
celery之Chains, Groups, Chords, Map & Starmap, Chunks
子任务支持如下 5 种原语,实现工作流. 原语表示由若干指令组成的, 用于完成一定功能的过程.
celery -A myproject worker -l info
-A:指定 celery 实例所在哪个模块中
-l: loglevel
celery -A myproject beat -l info
beta周期性的向任务队列中放入任务(是依赖worker去处理的)
如下: 调用task装饰的func.apply_async就是异步执行,或者调用send_task。
app = Celery("task", broker="redis://localhost:6379/0", backend="redis://localhost:6379/1")
@app.task
def add(x, y):
return x + y
@app.task
def tsum(numbers):
return sum(numbers)
@app.task
def trange(limit):
return range(limit)
result = add.apply_async((2, 2), link=add.s(16))
- (Chains)串行调用: 可以将signature任务按照顺序执行,前一个任务的输出是后一个任务的输入,结果是最后一个signature任务的输出。
from celery import chain
result = chain(add.s(2, 2), add.s(4), add.s(8))() # 2 + 2 + 4 + 8
result.get() # 16
result.parent.parent.graph
# cd959635-47d2-4368-bdf1-ab969f9ce0e4(1)
# 6681c6b6-bc34-44b4-8c9f-7ad132ffa5f3(0)
# 6681c6b6-bc34-44b4-8c9f-7ad132ffa5f3(0)
# 87eac0e5-1f1b-4c0d-a27a-dbf7e7ccd925(2)
# cd959635-47d2-4368-bdf1-ab969f9ce0e4(1)
# 6681c6b6-bc34-44b4-8c9f-7ad132ffa5f3(0)
- (Groups)并行调用:可以让signature并行执行,返回的结果是所有signature任务返回结果组成的数组。
from celery import group
result = group(add.s(2, 2), add.s(4, 4), add.s(8, 8))() # 2 + 2, 4 + 4, 8 + 8
result.get() # [14, 8, 16]
- (Chords)先并行,后串行: 把并行signature任务的结果列表输入到串行调用,进行汇总,是reduce过程。
from celery import group, chain, chord
result = chain(group(add.s(2, 2), add.s(4, 4), add.s(8, 8)), tsum.s())() # sum([2 + 2, 4 + 4, 8 + 8])
result.get() # 28
result = chord((add.s(2, 2), add.s(4, 4), add.s(8, 8)), tsum.s())()
result.get() # 28
- (Map)对并行调用的结果各自汇总
~tsum.map([range(2), range(2), range(2)]) # [1, 1, 1]
result = chain(trange.s(2), group(tsum.s(), tsum.s(), tsum.s()))()
result.get() # [1, 1, 1]
- (Starmap)对并行调用的结果各自汇总,汇总参数是tuple,相当于*args
~add.starmap(zip(range(10), range(10))) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
- (chunks)对大任务进行分割,分成小块执行,提高性能,将结果收集成列表。
result = add.chunks(zip(range(100), range(100)), 10)()
result.get()
#[[0, 2, 4, 6, 8, 10, 12, 14, 16, 18],
# [20, 22, 24, 26, 28, 30, 32, 34, 36, 38],
# [40, 42, 44, 46, 48, 50, 52, 54, 56, 58],
# [60, 62, 64, 66, 68, 70, 72, 74, 76, 78],
# [80, 82, 84, 86, 88, 90, 92, 94, 96, 98],
# [100, 102, 104, 106, 108, 110, 112, 114, 116, 118],
# [120, 122, 124, 126, 128, 130, 132, 134, 136, 138],
# [140, 142, 144, 146, 148, 150, 152, 154, 156, 158],
# [160, 162, 164, 166, 168, 170, 172, 174, 176, 178],
# [180, 182, 184, 186, 188, 190, 192, 194, 196, 198]]
配置和监控
celery -A tasks shell #调试, 类似django management.py shell
signal: 任务执行进度查看
- 方法1: 直接修改状态值,然后获取
#
@app.task
def Task_A(message):
# 这里就是在更新进度
Task_A.update_state(state='PROGRESS', meta={'progress': 0})
time.sleep(10)
Task_A.update_state(state='PROGRESS', meta={'progress': 30})
time.sleep(10)
return message
# 查看进度
def get_task_status(task_id):
task = Task_A.AsyncResult(task_id)
status = task.state
progress = 0
if status == u'SUCCESS':
progress = 100
elif status == u'FAILURE':
progress = 0
elif status == 'PROGRESS':
progress = task.info['progress']
return {'status': status, 'progress': progress}
r = xxx.delay()
r.ready() # 查看任务状态,返回布尔值, 任务执行完成, 返回 True, 否则返回 False.
r.get(timeout=1) # 获取任务执行结果,可以设置等待时间
r.result # 任务执行结果.
r.state # PENDING, START, SUCCESS,任务当前的状态
r.status # PENDING, START, SUCCESS,任务当前的状态
r.successful # 任务成功返回true
r.traceback # 如果任务抛出了一个异常,你也可以获取原始的回溯信息
r.wait() # 等待任务完成, 返回任务执行结果,很少使用;
- 方法2: 自定义进度msg
from task import add,test_mes
import sys
def pm(body):
res = body.get('result')
if body.get('status') == 'PROGRESS':
sys.stdout.write('\r任务进度: {0}%'.format(res.get('p')))
sys.stdout.flush()
else:
print '\r'
print res
r = test_mes.delay()
print r.get(on_message=pm, propagate=False)
- 方法3: signal回调方式获取状态
信号可以帮助我们了解任务执行情况, 分析任务运行的瓶颈. Celery 支持 7 种信号类型.
任务状态回调
钩子函数 | 状态值 | 说明 |
---|---|---|
before_task_publish | - | - |
after_task_publish | - | - |
task_prerun | PENDING | 任务等待中 |
task_postrun | STARTED | 任务已开始 |
task_retry | RETRY | 任务将被重试 |
task_success | SUCCESS | 任务执行成功 |
task_failure | FAILURE | 任务执行失败 |
task_revoked | REVOKED | 任务取消 |
每个任务的声明周期都会触发
@after_task_publish.connect
def task_sent_handler(sender=None, body=None, **kwargs):
print("hello world")
print('after_task_publish for task id {body[id]}'.format(
body=body,
))
终止任务
from celery.task.control import inspect
inspect().active() # 对应celery命令也可以查询,在监控那章节
这将列出正在处理的活动任务的列表。 你可以在那里获得任务的id 。 一旦获得了任务的id,就可以通过使用以下终止任务
from celery.task.control import revoke
revoke(task_id, terminate=True)
[django]celery_redis探索的更多相关文章
- 免费开源的 HelloDjango 系列教程,结束还是开始?
作者:HelloGitHub-追梦人物 我们已经成功地开发了一个功能比较完备的个人博客,是时候来总结一下我们的工作了.博客系列完整的源代码地址: https://github.com/HelloGit ...
- Mysql事务探索及其在Django中的实践(二)
继上一篇<Mysql事务探索及其在Django中的实践(一)>交代完问题的背景和Mysql事务基础后,这一篇主要想介绍一下事务在Django中的使用以及实际应用给我们带来的效率提升. 首先 ...
- Mysql事务探索及其在Django中的实践(一)
前言 很早就有想开始写博客的想法,一方面是对自己近期所学知识的一些总结.沉淀,方便以后对过去的知识进行梳理.追溯,一方面也希望能通过博客来认识更多相同技术圈的朋友.所幸近期通过了博客园的申请,那么今天 ...
- Django 探索(一) HelloWorld
一.Django怎么读 酱狗 二.Django下载 安装 下载地址 安装: tar zxvf Django-1.5.4.tar.gz python setup.py install 三.建立一个Hel ...
- Django框架的探索
django框架的路由 django2 路由支持正则匹配,如: re_path(r'^category/(?P<category_id>\d+)/$',CourseCategoryView ...
- 探索Django验证码功能的实现 - DjangoStarter项目模板里的封装
前言 依然是最近在做的这个项目,用Django做后端,App上提交信息的时候需要一个验证码来防止用户乱提交,正好我的「DjangoStarter」项目脚手架也有封装了验证码功能,不过我发现好像里面只是 ...
- 探索 Python/Django 支持分布式多租户数据库,如 Postgres+Citus
在 确定分布策略 中,我们讨论了在多租户用例中使用 Citus 所需的与框架无关的数据库更改. 在这里,我们专门研究如何借助 django-multitenant 库将多租户 Django 应 用程序 ...
- django 1.7+ default_permissions
由于做Caption要做权限设计.在核心类的设计的时候需要做好权限的基础设计.django 1.7+以后 django.db.modes新增特性 default_permissions,官方文档语焉不 ...
- django 2
创建一个管理员用户 首先,我们需要创建一个用户可以登录到管理网站. 运行 下面的命令: $ python manage.py createsuperuser 输入你想要的用户名,按回车. Userna ...
随机推荐
- WebService连接postgresql( 失败尝试)
一.先进行postgresql的配置 1. 安装ODBC驱动 下载地址:http://www.postgresql.org/ftp/odbc/versions/msi/ 2. 打开 控制面板 -&g ...
- AndroidのTextView之CompoundDrawable那些坑
TextView有几个属性android:drawableXXX,通常是在环绕文字周边显示一个图像,但是这有个坑就是文字和图片可能会对不齐. 纵使你设置gravity还是layout_gravity= ...
- 布式实时日志系统(三) 环境搭建之centos 6.4下hadoop 2.5.2完全分布式集群搭建最全资料
最近公司业务数据量越来越大,以前的基于消息队列的日志系统越来越难以满足目前的业务量,表现为消息积压,日志延迟,日志存储日期过短,所以,我们开始着手要重新设计这块,业界已经有了比较成熟的流程,即基于流式 ...
- KMP算法的实现(Java语言描述)
标签:it KMP算法是模式匹配专用算法. 它是在已知模式串的next或nextval数组的基础上执行的.如果不知道它们二者之一,就没法使用KMP算法,因此我们需要计算它们. KMP算法由两部分组成: ...
- MFC 消息映射表和虚函数实现消息映射到底谁的效率高
深入浅出MFC对于虚函数实现方式的缺点,它指出:虚函数耗费大量内存,系统最终将被这些额外负担拖垮. 但是现在对于容量巨大的白菜价格的内存来说,这种额外负担是否已经过时了呢~? 书中提到,虚函数表 ...
- SSL & TLS & STARTTLS
https://www.fastmail.com/help/technical/ssltlsstarttls.html SSL vs TLS vs STARTTLS There's often qui ...
- 设置RabbitMQ远程ip登录
由于账号guest具有所有的操作权限,并且又是默认账号,出于安全因素的考虑,guest用户只能通过localhost登陆使用,并建议修改guest用户的密码以及新建其他账号管理使用rabbitmq. ...
- vue生成路由实例
一.vue路由https://router.vuejs.org/zh-cn/1.bower下载vue-routervue的里的链接 <router-link to="/home&quo ...
- python nose测试框架全面介绍八---接口测试中非法参数的断言
在测接口时,会有这样的场景,输入非法的参数,校验返回的错误码及错误内容 通常做法为发请求,将错误的返回结果拿出,再进行对比匹配:但存在一个问题,需要再写错误返回分析函数,不能与之前正常发请求的函数共用 ...
- 使用shell数据处理数据实例①-------手把手教学版
引子: 在工作过程中经常要处理各种小数据,同事间会用各种工具方法来处理,比如用java.python.Perl甚至用UE手工处理.但貌似不都方便. 今天举一例子使用shell来处理,来说明shell一 ...