转载至 JmilkFan_范桂飓:http://blog.csdn.net/jmilk 

目录

前文列表

分布式任务队列 Celery
分布式任务队列 Celery —— 详解工作流
分布式任务队列 Celery —— 应用基础

前言

紧接前文,继续深入了解 Celery Tasks。示例代码依旧在前文的基础上进行修改。

​Tasks 是 Celery 的基石,原型类为 celery.app.task:Task,它提供了两个核心功能:

  • 将任务消息发送到队列
  • 声明 Worker 接收到消息后需要执行的具体函数

Task 的实例化

使用装饰器 app.task 来装饰一个普通函数,就可以轻松创建出一个任务函数。

from proj.celery import app

@app.task
def add(x, y):
return x + y

值得注意的是,任务函数本质上已经不再是一个普通函数,而是一个 celery.app.task:Task 实例对象。

>>> from proj.task.tasks import add
>>> dir(add)
['AsyncResult', 'MaxRetriesExceededError', ..., 'apply_async', 'delay', u'name', 'on_bound', 'on_failure', 'on_retry', 'on_success', 'request', 'retry', 'subtask', ...]

所以任务函数才可以调用 delay/apply_async 等属于 Task 的实例属性和方法。

>>> add.apply_async
<bound method add.apply_async of <@task: proj.task.tasks.add of proj at 0x7fedb363a790>>
>>> add.delay
<bound method add.delay of <@task: proj.task.tasks.add of proj at 0x7fedb363a790>>

这是一个非常重要的认识「app.task 的 “装饰” 动作,其实是 Task 的实例化过程」,而装饰器的参数就是 Task 初始化的参数。
官方文档(http://docs.celeryproject.org/en/latest/userguide/tasks.html#list-of-options)提供了完整的 app.task 装饰器参数列表。

除此之外,还需要注意「多装饰器顺序」的坑,app.task 应该始终放到最后使用,才能保证其稳定有效。

app.task
@decorator2
@decorator1
def add(x, y):
return x + y

任务的名字

每个任务函数都具有唯一的名字,这个名字被包含在任务消息中,Worker 通过该名字来找到具体执行的任务函数。默认的,Task 会启用自动命名,将函数的全路径名作为任务名。

>>> add.name
u'proj.task.tasks.add'

当然了,也可以通过指定装饰器参数 name 来指定任务名。

@app.task(name='new_name')
def add(x, y):
return x + y
>>> from proj.task.tasks import add
>>> add.name
'new_name'

但为了避免命名冲突的问题,一般不建议这么做,除非你很清楚自己的做什么。

任务的绑定

既然任务函数本质是一个 Task 实例对象,那么当然也可以应用 self 绑定特性。

# 启用绑定:
@app.task(bind=True)
def add(self, x, y):
print("self: ", self)
return x + y
>>> add.delay(1, 2)
<AsyncResult: 1982dc85-694b-4ceb-849b-5f69e40b4fe9>

绑定对象 self 十分重要,Task 的很多高级功能都是依靠它作为载体来调用的。例如:任务重试功能,请求上下文功能。

任务的重试

任务重试功能的实现为 Task.retry,它将任务消息重新发送到同一个的队列中,以此来重启任务。

@app.task(bind=True, max_retries=3)
def send_twitter_status(self, oauth, tweet):
try:
twitter = Twitter(oauth)
twitter.update_status(tweet)
except (Twitter.FailWhaleError, Twitter.LoginError) as exc:
raise self.retry(exc=exc)
  • max_retries 指定了最大的重试次数
  • exc 指定将异常信息输出到日志,需要开启 result backend。

如果你仅希望触发特定异常时才进行重试,可以应用 Task 的「Automatic retry for known exceptions」特性。

# 只有在触发 FailWhaleError 异常时,才会重试任务,且最多重试 5 次。
@app.task(autoretry_for=(FailWhaleError,), retry_kwargs={'max_retries': 5})
def refresh_timeline(user):
return twitter.refresh_timeline(user)

任务的请求上下文

在 Celery 请求 Worker 执行任务函数时,提供了请求的上下文,这是为了让任务函数在执行过程中能够访问上下文所包含的任务状态和信息。

@app.task(bind=True)
def dump_context(self, x, y):
print('Executing task id {0.id}, args: {0.args!r} kwargs: {0.kwargs!r}'.format(
self.request))
>>> from proj.task.tasks import dump_context
>>> dump_context.delay(1, 2)
<AsyncResult: 00bc9f96-98df-4bca-a4a3-4774c535a44c>

捕获请求上下文中的有用信息,有利于我们去分辨和调查一个任务的执行状况。
完整的上下文属性列表,可以查阅官方文档(http://docs.celeryproject.org/en/latest/userguide/tasks.html#task-request)。

任务的继承

使用 app.task 装饰器默认会实例化原生的 Task 类,这虽然能满足大部分的应用场景需求,但并非全部。所以 Celery 允许我们通过继承 Task 类,来衍生出特异化的基类。这一特性在复杂的应用场景中将会十分有效。

  • 重新指定适用于的所有任务的默认基类
def make_app(context):
app = Celery('proj')
app.config_from_object('proj.celeryconfig') default_exchange = Exchange('default', type='direct')
web_exchange = Exchange('task', type='direct')
app.conf.task_default_queue = 'default'
app.conf.task_default_exchange = 'default'
app.conf.task_default_routing_key = 'default' app.conf.task_queues = (
Queue('default', default_exchange, routing_key='default'),
Queue('high_queue', web_exchange, routing_key='hign_task'),
Queue('low_queue', web_exchange, routing_key='low_task'),
) app.conf.timezone = 'Asia/Shanghai'
app.conf.beat_schedule = {
'periodic_task_add': {
'task': 'proj.task.tasks.add',
'schedule': crontab(minute='*/1'),
'args': (2, 2)
},
} TaskBase = app.Task class ContextTask(TaskBase): abstract = True
context = ctx def __call__(self, *args, **kwargs):
"""Will be execute when create the instance object of ContextTesk.
"""
LOG.info(_LI("Invoked celery task starting: %(name)s[%(id)s]"),
{'name': self.name, 'id': self.request.id})
return super(ContextTask, self).__call__(*args, **kwargs) # 任务执行成功前做什么
def on_success(self, retval, task_id, args, kwargs):
"""Invoked after the task is successfully execute.
"""
LOG.info(_LI("Task %(id)s success: [%(ret)s]."),
{'id': task_id, 'ret': retval})
return super(ContextTask, self).on_success(retval, task_id,
args, kwargs) # 任务执行失败后做什么
def on_failure(self, exc, task_id, args, kwargs, einfo):
"""Invoked after the task failed to execute.
"""
msg = _LE("Task [%(id)s] failed:\n"
"args : %(args)s\n"
"kwargs : %(kw)s\n"
"detail :%(err)s") % {
'id': task_id, 'args': args,
'kw': kwargs, 'err': six.text_type(exc)}
LOG.exception(msg)
return super(ContextTask, self).on_failure(exc, task_id, args,
kwargs, einfo) # 重新赋予默认基类
app.Task = ContextTask
return app
  • 为不同类型的任务继承出具有偏向属性的基类
Import celery

class JSONTask(celery.Task):

    serializer = 'json'

    def on_failure(self, exc, task_id, args, kwargs, einfo):
print('{0!r} failed: {1!r}'.format(task_id, exc)) class XMLTask(celery.Task): serializer = 'xml' def on_failure(self, exc, task_id, args, kwargs, einfo):
print('{0!r} failed: {1!r}'.format(task_id, exc)) # 指定不同的基类
@task(base=JSONTask)
def add_json(x, y):
raise KeyError() # 指定不同的基类
@task(base=XMLTask)
def add_xml(x, y):
raise KeyError()

分布式任务队列 Celery —— Task对象的更多相关文章

  1. 分布式任务队列 Celery —— 深入 Task

    目录 目录 前文列表 前言 Task 的实例化 任务的名字 任务的绑定 任务的重试 任务的请求上下文 任务的继承 前文列表 分布式任务队列 Celery 分布式任务队列 Celery -- 详解工作流 ...

  2. [源码解析] 并行分布式任务队列 Celery 之 Task是什么

    [源码解析] 并行分布式任务队列 Celery 之 Task是什么 目录 [源码解析] 并行分布式任务队列 Celery 之 Task是什么 0x00 摘要 0x01 思考出发点 0x02 示例代码 ...

  3. [源码分析] 分布式任务队列 Celery 之 发送Task & AMQP

    [源码分析] 分布式任务队列 Celery 之 发送Task & AMQP 目录 [源码分析] 分布式任务队列 Celery 之 发送Task & AMQP 0x00 摘要 0x01 ...

  4. 分布式任务队列 Celery —— 应用基础

    目录 目录 前文列表 前言 Celery 的周期定时任务 Celery 的同步调用 Celery 结果储存 Celery 的监控 Celery 的调试 前文列表 分布式任务队列 Celery 分布式任 ...

  5. 分布式任务队列 Celery —— 详解工作流

    目录 目录 前文列表 前言 任务签名 signature 偏函数 回调函数 Celery 工作流 group 任务组 chain 任务链 chord 复合任务 chunks 任务块 mapstarma ...

  6. 分布式任务队列 Celery

    目录 目录 前言 简介 Celery 的应用场景 架构组成 Celery 应用基础 前言 分布式任务队列 Celery,Python 开发者必备技能,结合之前的 RabbitMQ 系列,深入梳理一下 ...

  7. [源码解析] 分布式任务队列 Celery 之启动 Consumer

    [源码解析] 分布式任务队列 Celery 之启动 Consumer 目录 [源码解析] 分布式任务队列 Celery 之启动 Consumer 0x00 摘要 0x01 综述 1.1 kombu.c ...

  8. [源码解析] 并行分布式任务队列 Celery 之 消费动态流程

    [源码解析] 并行分布式任务队列 Celery 之 消费动态流程 目录 [源码解析] 并行分布式任务队列 Celery 之 消费动态流程 0x00 摘要 0x01 来由 0x02 逻辑 in komb ...

  9. [源码解析] 并行分布式任务队列 Celery 之 多进程模型

    [源码解析] 并行分布式任务队列 Celery 之 多进程模型 目录 [源码解析] 并行分布式任务队列 Celery 之 多进程模型 0x00 摘要 0x01 Consumer 组件 Pool boo ...

随机推荐

  1. failOnMissingWebXml

    使用maven创建项目时有时在pom.xml的war处出现failOnMissingWebXml的错误,根据错误提示的原因可以知道项目是web项目,打包时打成war包. 如果项目里没有web.xml, ...

  2. Matplotlib数据可视化基础

    import numpy as np import matplotlib.pyplot as plt ## %matplotlib inline表示在行中显示图片,在命令行运行报错 data = np ...

  3. 剑指offer难题代码

    重建二叉树 题目描述 输入某二叉树的前序遍历和中序遍历的结果,前重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.假如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序 ...

  4. ES 数据类型

    官网数据类型网址 有价值的参考博客 本文 Elasticsearch 版本为 7.2 1. 核心数据类型 (1)字符串类型: text, keyword (2)数字类型:long, integer, ...

  5. Java文章翻译

    一.基础 1.String 使用" "还是构造函数创建字符串? 画图说明字符串的不变性 在Java中字符串为什么是不可变的 Java中的字符串是按引用传递? 排名前十的Java字符 ...

  6. C#开发者必须知道的13件事情

    1.开发流程 程序的Bug与瑕疵往往出现于开发流程当中.只要对工具善加利用,就有助于在你发布程序之前便将问题发现,或避开这些问题. 标准化代码书写 标准化代码书写可以使代码更加易于维护,尤其是在代码由 ...

  7. 【leetcode算法-简单】14. 最长公共前缀

    [题目描述] 编写一个函数来查找字符串数组中的最长公共前缀. 如果不存在公共前缀,返回空字符串 "". 示例 1: 输入: ["flower","fl ...

  8. Shortest Unsorted Continuous Subarray

    Given an integer array, you need to find one continuous subarray that if you only sort this subarray ...

  9. Windows 与 linux文件相互传输的方法

    公司里面办公机器大部分都是 windows 但是现在随着云计算.docker.linux等的越来越兴起,需要大量的操作linux服务器. 最重要和最直接的需要将windows 上面的文件上传到 lin ...

  10. IDEA操作之test case coverage的方法

    作用:  用于自动化测试,检查单元测试的覆盖率情况. 安装: 1.点击 Run * with coverage 或者右键已经定义为test source的package选择(单个test class同 ...