Celery消息隊列----路由任務

基礎

自動路由

最簡單的路由方式是使用 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'}
    },
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章