基礎
自動路由
最簡單的路由方式是使用 task_create_missing_queues 設置 (默認是開啓的)。
這個設置開啓後, 一個在task_queues中還未定義的命名隊列會被自動創建。這讓簡單的路由任務變得很容易。
假如你有兩臺服務器x 和 y,來處理常規(regular)任務,一個服務器z只處理feed相關的任務。你可以使用這樣的配置:
task_routes = {'feed.tasks.import_feed': {'queue': 'feeds'}}
這個路由啓用( enabled)後import_feed任務會被路由給“feeds”隊列, 並且所有其他任務會被路由到默認隊列(由於歷史原因這個隊列叫“celery”)。
除此以外,你可以使用全局模式匹配,或者正則表達式,匹配所有在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設置既可以是一個字典,也可是路由器對象的列表,所以在這種情況下我們需要指定設置爲一個包含列表的元組(tuple)。
配置好路由器後,你可以開啓服務器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'}
像Redis 或 SQS這樣的非AMQP的後端,不支持交易所(exchange),所以他們需要exchange同隊列有相同的名字。使用這個設計可以確保對他們也有效。
手動路由
假如你有兩臺服務器x 和 y,來處理常規(regular)任務,一個服務器z只處理feed相關的任務,你可以使用這樣的配置:
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_queues 是Queue 實例的列表.。如果你沒有給一個鍵設置exchange或者exchange類型,這些會從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隊列消費,你可以使用celery worker -Q 選項啓動它:
user@z:/$ celery -A proj worker -Q feed_tasks --hostname=z@%h
服務器 x 和 y 必須被配置成從默認隊列消費:
user@x:/$ celery -A proj worker -Q default --hostname=x@%h
user@y:/$ celery -A proj worker -Q default --hostname=y@%h
如果你想,甚至可以讓你的處理feed的工人(worker)也處理正規(regular)任務:
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。
。。。。。。。。。。。。。。。。
路由任務
定義隊列
在Celery中可用的隊列通過task_queues設置被定義。
這有一個隊列配置的例子,它配置了三個隊列;一個給video,一個給images還有一個給別的東西的默認隊列:
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中登記註冊(entries)的默認值。
也支持多重綁定到單一隊列。下面是兩個路由鍵都綁定到相同隊列的例子:
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'),
]),
)
指定任務終點Specifying task destination
一個任務的終點由下面來決定(按次序):
在task_routes中定義的Routers。
The Routers defined in task_routes.
給Task.apply_async()的路由參數。
The routing arguments to Task.apply_async().
定義在Task自身中的路由相關的屬性。
Routing related attributes defined on the Task itself.
一般最好不要硬編碼這些設置,而是通過使用Routers把那個作爲配置選項。這是最靈活的途徑,但明確合理的默認值仍然可以被設置爲任務屬性。
路由器Routers
路由器是一個爲任務決定路由選項的的函數。A router is a function that decides the routing options for a task.
定義一個新路由器時,你所要做的就是定義一個函數,帶有簽名 (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_queues中的那個隊列已定義的設置進行擴展:
{'queue': 'video', 'routing_key': 'video.compress'}
變成 –>
{'queue': 'video',
'exchange': 'video',
'exchange_type': 'topic',
'routing_key': 'video.compress'}
通過把他們添加到task_routes設置中來配置路由器類:
task_routes = (route_task,)
Router 函數也可以通過名字添加:
task_routes = ('myapp.routers.route_task',)
對於簡單的任務名For simple task name -> 路由映射就像上面的路由器例子,你可以簡單的把一個字典放到task_routes中,獲取同樣的表現:
task_routes = {
'myapp.tasks.compress_video': {
'queue': 'video',
'routing_key': 'video.compress',
},
}
路由器們(routers)會被按次序探查,在第一個返回真值的路由器處停止,選擇它作爲任務的最終路由。
你也可以在一個序列中定義多個路由器:
task_routes = [
route_task,
{
‘myapp.tasks.compress_video’: {
‘queue’: ‘video’,
‘routing_key’: ‘video.compress’,
},
]
路由器會被按次序訪問,第一個返回值的會被選中。
廣播Broadcast
Celery 也支持廣播路由。這有一個 broadcast_tasks交易所的例子,它會傳遞任務的拷貝給所有連接到它的工人(workers)。:
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定時器:
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'}
},
}