目录

前文列表

分布式任务队列 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是什么

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

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

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

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

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

  4. [源码分析] 并行分布式任务队列 Celery 之 Timer & Heartbeat

    [源码分析] 并行分布式任务队列 Celery 之 Timer & Heartbeat 目录 [源码分析] 并行分布式任务队列 Celery 之 Timer & Heartbeat 0 ...

  5. 分布式任务队列 Celery —— Task对象

    转载至 JmilkFan_范桂飓:http://blog.csdn.net/jmilk  目录 目录 前文列表 前言 Task 的实例化 任务的名字 任务的绑定 任务的重试 任务的请求上下文 任务的继 ...

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

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

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

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

  8. 分布式任务队列 Celery

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

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

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

随机推荐

  1. 使用CXF开发WebService程序的总结(三):创建webservice客户端

    1.创建一个maven子工程 ws_client,继承父工程 1.1 修改父工程pom配置 <modules> <module>ws_server</module> ...

  2. Ajax跳入error的原因

    1. dataType错误 我遇到的就是这个dataType错误,即后台返回的dataType类型与前台写的不一致,一般前台写json没问题,大部分是后台返回的类型对不上 2. async请求同步异步 ...

  3. windows2008R2下安装sqlserver2008R2时,点setup.exe应用程序无法打开错误代码0xc0150004

    windows2008R2下安装sqlserver2008R2时,点setup.exe应用程序无法打开错误代码0xc0150004 问题截图: 网上查的答案都是需要安装.net framework 3 ...

  4. 实现MD5算法

    using System; using System.Text; using System.Security.Cryptography; namespace Common { /// <summ ...

  5. hdu 6501 transaction transaction transaction 最长路/树形DP/网络流

    最长路: 设置一个虚拟起点和虚拟终点,每个点与起点间一条负边,值为这个点书的价值的相反数(代表买书花钱),每个点与终点连一条正边,值为这个点的书的价格(代表卖书赚钱). 然后按照图中给的边建无向边,权 ...

  6. ui自动化之selenium操作(三)xpath定位

    xpath 的定位方法,非常强大.使用这种方法几乎可以定位到页面上的任意元素. 1. 什么是xpath? xpath 是XML Path的简称, 由于HTML文档本身就是一个标准的XML页面,所以我们 ...

  7. Fiddler抓包的简单使用

    Fiddler抓包的简单使用 参考的博客文章:玲虫师的<Fiddler抓包[5]_Fiddler过滤>. (1)使用fiddler进行过滤,只抓取需要的网络请求. 点击右侧菜单中的[Fil ...

  8. "东坡肉”

    “东坡肉” 苏东坡成名后,求师的人蜂涌而至,有学书法的,有学文章的.也有这么一个人,人问他学什么?他说:我学的是“东坡肉”呢! 苏东坡会不会煮猪肉?从他咏黄州猪肉“慢著火.少著水.火候足时它自美”的诗 ...

  9. 大数据(量上GB的)查看命令

    大数据查看指令 cmd中(tab键可补全) type 文件名:全部查看 more 文件名:Enter键,按一下查看一页

  10. Django 视图层和模板层

    目录 一.网站首页和404页面的路由配置 1. 网站首页路由 2. 404页面 二.Django视图层 1. 小白必会三板斧 (1)HttpResponse (2)render (3)redirect ...