Celery-4.1 用户指南: Routing Tasks (路由任务)
注意:
像主题和扇出之类的路由概念并不对所有传输介质都可用,请翻阅”传输比较表”。
基础
自动路由
路由最简单的方式是使用 task_create_missing_queues 设置(默认启用)。
使用这个设置,一个还没有在 task_queues 中定义的有名队列将会自动被创建。这使得进行简单的路由任务非常容易。
假如你有两台服务器,x 和 y 处理常规任务,还有一台服务器 z,只处理feed消息源相关的任务。你可以使用这个配置:
task_routes = {'feed.tasks.import_feed': {'queue': 'feeds'}}
使用这个路由使得导入消息源任务被路由到feeds队列,而所有其他任务都将路由到默认队列(由于历史原因默认队列名为 celery)。
或者,你可以使用glob模式匹配,甚至可以用正则表达式,来匹配feed.tasks命名空间里的所有任务:
app.conf.task_routes = {'feed.tasks.*': {'queue': 'feeds'}}
如果匹配模式的顺序很重要,你应该以项列表的格式声明路由:
task_routes = ([
('feed.tasks.*', {'queue': 'feeds'}),
('web.tasks.*', {'queue': 'web'}),
(re.compile(r'(video|image)\.tasks\..*'), {'queue': 'media'}),
],)
注意:
task_routes 设置可以是一个字典,或者一个路由对象的列表,所以在上述情况下,你需要以一个包含列表的元组的方式声明 task_routes。
安装好路由器后,你可以启动服务器 z 用来专门处理 feeds 消息源队列:
user@z:/$ celery -A proj worker -Q feeds
你可以声明你需要的多个队列,所以你也可以让你的服务器处理默认队列的消息:
user@z:/$ celery -A proj worker -Q feeds,celery
修改默认队列的名称
你可以使用下列配置修改默认队列的名称:
app.conf.task_default_queue = 'default'
队列是如何被定义的
这个特性的重点在于为只有基本需求的用户隐藏了复杂的 AMQP 协议。但是 - 你可能对队列是如何声明的仍然感兴趣。
一个名为 video 的队列将使用下列配置创建:
{'exchange': 'video',
'exchange_type': 'direct',
'routing_key': 'video'}
非 AMQP 后端如 Redis 或者 SQS 不支持消息交换器,所以他们需要消息交换器与队列同名。使用这种设计使得它可以在不会吃消息交换器的后端也能正常工作。
手动路由
假如你又两台服务器 x 和 y 处理常规任务,另外一台服务器 z,用来专门处理消息源相关的任务,你可以使用如下配置:
from kombu import Queue app.conf.task_default_queue = 'default'
app.conf.task_queues = (
Queue('default', routing_key='task.#'),
Queue('feed_tasks', routing_key='feed.#'),
)
task_default_exchange = 'tasks'
task_default_exchange_type = 'topic'
task_default_routing_key = 'task.default'
task_queue 是一个队列实例的列表。如果你没有为一个 key 设置消息交换器或者交换器类型,这些信息将从 task_default_exchange 和 task_default_exchange_type 配置中获取。
路由一个任务到 feed_tasks 队列,你可以在 task_routes 配置种添加一个项:
task_routes = {
'feeds.tasks.import_feed': {
'queue': 'feed_tasks',
'routing_key': 'feed.import',
},
}
你可以使用Task.apply_async()方法或者 send_task() 方法的 routing_key 参数覆盖这个路由行为:
>>> from feeds.tasks import import_feed
>>> import_feed.apply_async(args=['http://cnn.com/rss'],
... queue='feed_tasks',
... routing_key='feed.import')
使服务器 z 只从 feed_tasks 队列获取消息,你可以启动工作单元时使用 -Q 选项:
user@z:/$ celery -A proj worker -Q feed_tasks --hostname=z@%h
服务器 x 和 y 必须配置成从default队列获取消息:
user@x:/$ celery -A proj worker -Q default --hostname=x@%h
user@y:/$ celery -A proj worker -Q default --hostname=y@%h
如果你愿意,你甚至可以让的消息源处理工作单元也处理常规任务,也许在有许多常规任务的时候:
user@z:/$ celery -A proj worker -Q feed_tasks,default --hostname=z@%h
如果你想添加在另外一个消息交换器上一个队列,只要声明自定义消息交换器及它的类型即可。
from kombu import Exchange, Queue app.conf.task_queues = (
Queue('feed_tasks', routing_key='feed.#'),
Queue('regular_tasks', routing_key='task.#'),
Queue('image_tasks', exchange=Exchange('mediatasks', type='direct'),
routing_key='image.compress'),
)
如果你对这些术语有不清楚的地方,你应该去看看 AMQP。
另见:
处理下面的 AMQP Primer,还有 Rabbits and Warrens 这个讲述队列和消息交换的优秀的博客。另外,还有一个 CloudAMQP tutorial,对于 RabbitMQ 用户来说, RabbitMQ FAQ 将是非常有用的。
特殊的路由选项
RabbitMQ 消息优先级
supported transports:
RabbitMQ
4.0版本新特性。
队列可以通过设置 x-max-priority 参数支持优先级:
from kombu import Exchange, Queue app.conf.task_queues = [
Queue('tasks', Exchange('tasks'), routing_key='tasks',
queue_arguments={'x-max-priority': 10},
]
所有队列的优先级默认值使用 task_queue_max_priority 设置:
app.conf.task_queue_max_priority = 10
AMQP Primer
消息
消息包含消息头和消息体。Celery 使用消息头存储消息的内容类型和内容编码。内容类型通常是消息使用的序列化格式。消息体包含要执行的任务的名称,任务的id(UUID),任务函数的参数以及一个附加的元信息 - 如重试次数或者 ETA。
下面是一个使用 python 字典表示的任务消息的示例:
{'task': 'myapp.tasks.add',
'id': '54086c5e-6193-4575-8308-dbab76798756',
'args': [4, 4],
'kwargs': {}}
生产者,消费者,消息中间件
发送消息的客户端通常被称为发布者,或者生产者,而接收消息的实体被称为消费者。
消息中间件是一个消息服务器,它将消息从生产者路由到消费者。
下面这些术语在 AMQP 相关的文档里经常能看到。
Exchanges, 队列, 路由键
- 消息是发送给消息交换器
- 消息交换器将消息路由到一个或者多个队列。有几种不同的消息交换器类型,他们提供不同的路由方式,或者实现不同的消息场景
- 消息在队列中等待指导有人消费它
- 当消息被确认它将从队列中删除
收发消息的必要步骤包括:
1. 创建一个消息交换器
2. 创建一个队列
3. 将队列绑定到消息交换器
Celery 自动创建 task_queues 中定义的队列所需要的实体(除非队列的 auto_declare 设置为 False)。
下面是队列配置示例包含三个队列;Video 处理一个,images 处理一个,以及其他处理的 default 队列:
from kombu import Exchange, Queue app.conf.task_queues = (
Queue('default', Exchange('default'), routing_key='default'),
Queue('videos', Exchange('media'), routing_key='media.video'),
Queue('images', Exchange('media'), routing_key='media.image'),
)
app.conf.task_default_queue = 'default'
app.conf.task_default_exchange_type = 'direct'
app.conf.task_default_routing_key = 'default'
Exchange 类型
消息交换器类型定义了消息怎样通过消息交换器路由。标准的消息交换器类型有 direct,topic,fanout以及headers。另外,非标准的消息交换器类型可以通过 RabbitMQ 插件的方式使用,例如 Michael Bridgen 写的 last-value-cache plugin。
Direct exchanges
直接消息交换类型通过精确的路由键匹配实现路由,所以一个被路由键 video 绑定的队列只能收到这个带这个路由键的消息。
Topic exchanges
主题消息交换类型使用 . 分隔单词,wild-card 字符 *(匹配整个词),字符#(匹配零个或多个词) 的方式匹配路由键。
对于类似 usa.news, usa.weather, norway.news, 以及 norway.weather 的路由键,绑定可以是 *.news(all news),usa.# (all items in the USA),or usa.weather (all USA weather items)
相关 API 命令
- exchange.declare(exchange_name, type, passive,
durable, auto_delete, internal)
使用名称声明一个消息交换器。
查看 amqp:Channel.exchange_声明。
关键字参数:
passive – 被动意味着消息交换器不会被自动创建,你可以使用它来检测消息交换器是否存在。
durable – Durable 消息交换器是持久的 (即, 消息中间件重启他们还存在)。
auto_delete – 这意味着如果没有队列使用它,消息中间件将会自动删除它。
- queue.declare(queue_name, passive, durable, exclusive, auto_delete)
使用名称声明一个队列。
查看 amqp:Channel.queue_声明。
专用队列只能在当前连接中被消费。专用也意味着 auto_delete。
- queue.bind(queue_name, exchange_name, routing_key)
使用路由键将一个队列绑定到一个消息交换器。
未绑定的队列不会收到消息,所以这是必须的。
查看 amqp:Channel.queue_bind。
- queue.delete(name, if_unused=False, if_empty=False)
Deletes a queue and its binding.
查看 amqp:Channel.queue_delete
exchange.delete(name, if_unused=False)
Deletes an exchange.
查看 amqp:Channel.exchange_delete
注意:
声明并不意味着“创建”。当你声明,你只是断言这个实体存在并且是可操作的。没有规定说谁应该创建 exchange/queue/binding,不论是消费者或者生产者。通常谁先需要它谁就创建它。
API 动手实践
Celery 有一个工具 celery amqp 用来从命令行访问 AMQP API,使得可以访问管理员的任务如创建/删除队列以及消息交换器,删除队列消息或者发送消息。对于非 AMQP 消息中间件它也可以使用,但是不同的实现可能没有实现所有的命令。
你可以直接在 celery amqp 的命令行参数中编写命令,或者不带任何参数启动进入到交互模式:
$ celery -A proj amqp
-> connecting to amqp://guest@localhost:5672/.
-> connected.
1>
这里 1> 是一个提示符。数字 1 表示你当前已经执行的命令。键入 help 获取可用命令的列表,它还支持自动补全,所以你可以开始键入命令,然后按tab键显示可用的匹配。
下面创建一个队列,你可以发送消息给它:
$ celery -A proj amqp
1> exchange.declare testexchange direct
ok.
2> queue.declare testqueue
ok. queue:testqueue messages:0 consumers:0.
3> queue.bind testqueue testexchange testkey
ok.
这里创建了一个直接类型的消息交互器 testexchange,以及一个名为 testqueue 的队列。这个队列使用路由键 testkey 绑定到消息交换器。
从此以后,所有带路由键 testkey发送到消息交换器 testexchange 的消息都将递送到这个队列。你可以使用 basic.publish 命令发送一个消息:
4> basic.publish 'This is a message!' testexchange testkey
ok.
现在消息已经发送,你可以获取它。你可以使用 basic.get 命令,它将以异步的方式从队列中获取消息(对于维护任务这是可行的,但是对于服务,你应该使用 basic.consume)。
从队列中取出一个消息:
5> basic.get testqueue
{'body': 'This is a message!',
'delivery_info': {'delivery_tag': 1,
'exchange': u'testexchange',
'message_count': 0,
'redelivered': False,
'routing_key': u'testkey'},
'properties': {}}
AMQP 使用确认机制来表示一个消息已经收到并且被成功处理。如果消息没有被确认并且消费者通道关闭,那么消息将重新递送到另一个消费者。
注意上述结构中的 delivery_tag, 在一个连接通道中,每个接收到的消息都有唯一的一个 delivery_tag,这个标记是用来确认消息的。另外,注意 delivery_tag 在不同连接通道中不是唯一的,所以在另一个客户端,递送标记 1 可能指向不同于这个通道的另一个消息。
你可以使用 basic.ack 确认你收到的消息:
6> basic.ack 1
ok.
清理我们测试会话的环境,你应该删除掉你创建的实体:
7> queue.delete testqueue
ok. 0 messages deleted.
8> exchange.delete testexchange
ok.
路由任务
定义队列
在 Celery 中,可用的队列是通过 task_queue 设置的。
下面是队列配置示例包含三个队列;Video 处理一个,images 处理一个,以及其他处理的 default 队列:
default_exchange = Exchange('default', type='direct')
media_exchange = Exchange('media', type='direct')
app.conf.task_queues = (
Queue('default', default_exchange, routing_key='default'),
Queue('videos', media_exchange, routing_key='media.video'),
Queue('images', media_exchange, routing_key='media.image')
)
app.conf.task_default_queue = 'default'
app.conf.task_default_exchange = 'default'
app.conf.task_default_routing_key = 'default'
这里,task_default_queue 将会被用来路由没有显示路由的任务。
默认消息交互器、消息交换类型以及路由键将会用作任务的默认路由值,并且作为 task_queues 中定义的队列的默认配置值。
一个队列多个绑定也是支持的。下面示例中两个路由键都绑定到了同一个队列:
from kombu import Exchange, Queue, binding
media_exchange = Exchange('media', type='direct')
CELERY_QUEUES = (
Queue('media', [
binding(media_exchange, routing_key='media.video'),
binding(media_exchange, routing_key='media.image'),
]),
)
声明任务目的地
任务的目的是由下列因素决定(按顺序)
1. task_routes 中定义的路由
2. Task.apply_async() 方法的路由参数
3. Task 本身定义的路由相关属性
最佳实践是不写硬编码这些设置,而是通过 Routers 将它作为配置选项;这是最灵活的方式,但是合理的默认值仍然可以设置称任务属性。
路由器
路由器是一个决定任务路由选项的函数。
定义一个路由器,你只需要定义签名未 (name, args, kwargs, options, task=None, **kw) 的函数:
def route_task(name, args, kwargs, options, task=None, **kw):
if name == 'myapp.tasks.compress_video':
return {'exchange': 'video',
'exchange_type': 'topic',
'routing_key': 'video.compress'}
如果你返回队列键,它将使用 ·task_queue 中该队列的设置扩展:
{'queue': 'video', 'routing_key': 'video.compress'}
扩展为 ->
{'queue': 'video',
'exchange': 'video',
'exchange_type': 'topic',
'routing_key': 'video.compress'}
你可以通过将路由添加到 task_routes 设置中来安装路由类:
task_routes = (route_task,)
路由函数还可以通过名称来添加:
task_routes = ('myapp.routers.route_task',)
对于上述这种简单的任务名称->路由的映射,你可以在 task_routes 设置中使用一个字典来达到同样的效果:
task_routes = {
'myapp.tasks.compress_video': {
'queue': 'video',
'routing_key': 'video.compress',
},
}
路由器将按顺序被遍历,直到遇到第一个返回真值的路由器,并使用它作为任务的最终路由。
你可以在一个序列中定义多个路由器:
task_routes = [
route_task,
{
'myapp.tasks.compress_video': {
'queue': 'video',
'routing_key': 'video.compress',
},
]
路由器将被按顺序访问,首先返回值的将被选中。
广播
Celery 还支持广播路由。下列消息交换器 broadcast_task 将任务的拷贝递送到连接它的所有工作单元:
from kombu.common import Broadcast
app.conf.task_queues = (Broadcast('broadcast_tasks'),)
app.conf.task_routes = {
'tasks.reload_cache': {
'queue': 'broadcast_tasks',
'exchange': 'broadcast_tasks'
}
}
现在,tasks.reload_cache 任务将递送到所有从这个队列消费的工作单元。
下面是另一个广播路由的示例,这次使用的是 celery beat 调度器:
from kombu.common import Broadcast
from celery.schedules import crontab app.conf.task_queues = (Broadcast('broadcast_tasks'),) app.conf.beat_schedule = {
'test-task': {
'task': 'tasks.reload_cache',
'schedule': crontab(minute=0, hour='*/3'),
'options': {'exchange': 'broadcast_tasks'}
},
}
广播结果:
注意 Celery 结果没有定义如果两个任务有相同的任务 ID 将发生什么。如果相同的任务分发到多于一个工作单元,那么状态历史可能不会保留。
这种情况下,设置 task.ignore_result 属性是一个不错的注意。
转自:https://blog.csdn.net/libing_thinking/article/details/78587375
Celery-4.1 用户指南: Routing Tasks (路由任务)的更多相关文章
- Celery-4.1 用户指南: Calling Tasks(调用任务)
基础 本文档描述 Celery 中任务实例和 Canvas 使用的统一 “Calling API”. API 中定义了一个执行选项的标准集,以及三个方法: - apply_async(args[, k ...
- Celery-4.1 用户指南: Periodic Tasks (定时任务)
简介 celery beat 是一个调度器:它以常规的时间间隔开启任务,任务将会在集群中的可用节点上运行. 默认情况下,入口项是从 beat_schedule 设置中获取,但是自定义的存储也可以使用, ...
- Celery-4.1 用户指南: Configuration and defaults (配置和默认值)
这篇文档描述了可用的配置选项. 如果你使用默认的加载器,你必须创建 celeryconfig.py 模块并且保证它在python路径中. 配置文件示例 以下是配置示例,你可以从这个开始.它包括运行一个 ...
- flume1.9 用户指南(中文版)
概述 Apache Flume是一个分布式,可靠且可用的系统,用于有效地从许多不同的source收集,聚合和移动大量日志数据到集中式数据存储. Apache Flume的使用不仅限于日志数据聚合.由于 ...
- Gradle用户指南
下载安装gradle 2.1 下载地址:http://www.gradle.org/learn 安装先决条件:gradle安装需要1.6或者更高版本的jdk(jre)(可以使用java –versio ...
- 【Flume NG用户指南】(1)设置
作者:周邦涛(Timen) Email:zhoubangtao@gmail.com 转载请注明出处: http://blog.csdn.net/zhoubangtao/article/details ...
- Android官方技术文档翻译——Gradle 插件用户指南(1-3)
不知道是什么网络问题,上午一直发不了博客,其它页面基本正常,就是在写博客这里,每次打开都是响应超时.刚才用了VPN,顺便试了一下,竟然能够编辑.想是CDN之类的问题吧. 这次翻译的是Gradle 插件 ...
- Android官方技术文档翻译——Gradle 插件用户指南(7)
本文译自Android官方技术文档<Gradle Plugin User Guide>,原文地址:http://tools.android.com/tech-docs/new-build- ...
- Android官方技术文档翻译——Gradle 插件用户指南(6)
没想到翻译这篇<Gradle 插件用户指南>拖了差不多一个月,还跨年了.不过还好,在2号时终于一口气把剩下的给翻译完了(其实那天剩下的也就不到一章). 今天先发一下第六章,明天再发第七章. ...
随机推荐
- 【P2325】王室联邦(树的遍历+贪心)
在肖明 #神#的推荐下,我尝试了这个题,一开始想的是暴力枚举所有的点,然后bfs层数,试着和肖明 #神#说了这种方法之后, #神#轻蔑的一笑,说这不就是一个贪心么,你只需要先建树,然后从底下向上遍历, ...
- android、ipone在文本框中输入文字的不同
1.android机会输入时会在键盘上先显示,你确定后再填充如文本框 2.ipone机是你输入时就直接填充到文本框,当你选择输入信息时,就会先把文本框的内容清空,在填充选择的文字,这时就会有个问题,如 ...
- 在移动端做查看日志信息的js
Vconsole.js下载这个js引入需要使用的html文件,当运行到页面是就会在右下角显示提示,点击就出出现像pc端上的控制台页面 在线查看的网址 http://console.hongliang. ...
- JavaWeb -- Jsp 和 JavaBean
JSP技术提供了三个关于JavaBean组件的动作元素,即JSP标签,它们分别为: <jsp:useBean>标签:用于在JSP页面中查找或实例化一个JavaBean组件. <jsp ...
- js职责链模式
职责链模式(Chain of Responsiblity),使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系.将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为 ...
- MDX中Filter 与Exist的区别
获得一个集合,这个一般用来筛选出一个自定义的set,比如在中国的餐厅 该set返回所有MSDNteam下并且在Fact Thread度量上有记录的products 用Exists实现 sele ...
- SSIS的控制流之Foreach循环容器和序列容器
上一篇介绍了For循环容器的使用.本篇将介绍Foreach循环容器和序列容器的使用. Foreach循环容器 Foreach循环容器定义包中的控制流.其循环的实现类似于编程语言中的Foreach循环结 ...
- Announcing the Release of ASP.NET MVC 5.1, ASP.NET Web API 2.1 and ASP.NET Web Pages 3.1 for VS2012
The NuGet packages for ASP.NET MVC 5.1, ASP.NET Web API 2.1 and ASP.NET Web Pages 3.1 are now live o ...
- 19条ANDROID平台设计规范平台设计规范
1.尺寸以及分辨率: Android的界面尺寸比较流行的有:480*800.720*1280.1080*1920,我们在做设计图的 时候建议是以 480*800的尺寸为标准: 2.界面基本组成元素: ...
- MYSQL 索引创建与使用
可能用到索引的地方: where 子句,order by,group by 不需要创建索引的情况: 1. 表比较小 2.赋值有限的列(枚举),不要创建索引.创建的索引返回的行越少越好,此时区分度大. ...