繁体   English   中英

使用主题交换运行多个 Celery 任务

[英]Run multiple Celery tasks using a topic exchange

我正在用 Celery 替换一些本土代码,但很难复制当前的行为。 我想要的行为如下:

  • 创建新用户时,应使用user.created路由键将消息发布到tasks交换。
  • 此消息应触发两个 Celery 任务,即send_user_activate_emailcheck_spam

我尝试通过使用ignore_result=True参数定义user_created任务以及send_user_activate_emailcheck_spam的任务来send_user_activate_email check_spam

在我的配置中,我添加了以下路由和队列定义。 当消息传递到user_created队列时,它不会传递到其他两个队列。

理想情况下,消息仅传送到send_user_activate_emailcheck_spam队列。 使用 vanilla RabbitMQ 时,消息被发布到一个交换器,队列可以绑定到该交换器,但 Celery 似乎直接将消息传递到队列。

我将如何在 Celery 中实现上述行为?

CELERY_QUEUES = {
    'user_created': {'binding_key':'user.created', 'exchange': 'tasks', 'exchange_type': 'topic'},
    'send_user_activate_email': {'binding_key':'user.created', 'exchange': 'tasks', 'exchange_type': 'topic'},
    'check_spam': {'binding_key':'user.created', 'exchange': 'tasks', 'exchange_type': 'topic'},
}

CELERY_ROUTES = {
    'user_created': {
        'queue': 'user_created',
        'routing_key': 'user.created',
        'exchange': 'tasks',
        'exchange_type': 'topic',
    },
    'send_user_activate_email': {
        'queue': 'user_created',
        'routing_key': 'user.created',
        'exchange': 'tasks',
        'exchange_type': 'topic',
    },
    'check_spam': {
        'queue': 'user_created',
        'routing_key': 'user.created',
        'exchange': 'tasks',
        'exchange_type': 'topic',
    },
}

听起来您希望单个消息触发/被两个队列使用,但这不是 Celery 的工作方式。 Exchange 会将任务发布到符合条件的队列,但是一旦它被消耗,其他队列就会忽略该消息。 每个要触发的任务都需要一条消息。

Celery 新用户经常会混淆,因为在这个系统中“队列”有两种用途; Queue() 和文档所引用的 Kombu 队列,以及直接保存消息并由工作人员使用的 AMQP 队列。 当我们发布到队列时,我们想到的是 AMQP 的,这是不正确的。 (感谢回答链接如下)。

回到你的问题,如果我理解正确,当 user_created 被消耗时,你希望它产生两个以上的任务; send_user_activate_email 和 check_spam。 此外,这些不应相互依赖; 它们可以在不同的机器上并行运行,不需要知道彼此的状态。

在这种情况下,您希望 user_created “apply_async”这两个新任务并返回。 这可以直接完成,或者您可以使用包含 check_spam 和 send_user_activate_email 的 Celery“组”来实现此目的。 该小组提供了一些不错的速记,并为您的任务提供了一些结构,因此我个人会向您推荐这个方向。

#pseudocode
group(check_spam.s(... checkspam kwargs ...), send_user_activate_email.s(... active email kwargs ...)).apply_async()

此设置将创建四个消息; 一个用于您要执行的每个任务,另外一个用于 Group(),这本身就会产生结果。

在您的情况下,我不确定 Exchange 或 ignore_result 是否必要,但我需要查看任务代码并更多地了解系统才能做出判断。

http://docs.celeryproject.org/en/latest/userguide/canvas.html#groups http://celery.readthedocs.org/en/v2.2.6/userguide/routing.html#exchanges-queues-and-routing -keys 为什么 CELERY_ROUTES 有“队列”和“路由密钥”?

(如果我离开我会删除/删除答案......)

设计和解决问题的简单方法是使用 Celery 工作流程。
但首先,我会更改您的队列定义,为每个任务设置唯一的路由键,并使用“直接”值设置 exchange_type。

根据celery 文档直接交换通过精确的路由键匹配,因此我们为所有自定义任务和消费者队列设置相同的交换,并像下一个片段一样映射 routing_key(用于任务)和 binding_key(用于队列):

CELERY_QUEUES = {
    'user_created': {'binding_key':'user_created', 'exchange': 'tasks', 'exchange_type': 'direct'},
    'send_user_activate_email': {'binding_key':'send_user_activate_email', 'exchange': 'tasks', 'exchange_type': 'direct'},
    'check_spam': {'binding_key':'check_spam', 'exchange': 'tasks', 'exchange_type': 'direct'},
}

CELERY_ROUTES = {
    'user_created': {
        'queue': 'user_created',
        'routing_key': 'user_created',
        'exchange': 'tasks',
        'exchange_type': 'direct',
    },
    'send_user_activate_email': {
        'queue': 'send_user_activate_email',
        'routing_key': 'send_user_activate_email',
        'exchange': 'tasks',
        'exchange_type': 'direct',
    },
    'check_spam': {
        'queue': 'check_spam',
        'routing_key': 'check_spam',
        'exchange': 'tasks',
        'exchange_type': 'direct',
    },
}

完成此更改后,您需要对可用列表 ( http://docs.celeryproject.org/en/latest/userguide/canvas.html#the-primitives ) 使用正确的工作流程。 阅读您的问题,我认为您需要一个链,因为需要保留顺序。

sequential_tasks = []
sequential_tasks.append(user_created.s(**user_created_kwargs))
sequential_tasks.append(send_user_activate_email.s(**send_user_activate_email_kwargs))
sequential_tasks.append(check_spam.s(**check_spam_kwargs))
#you can add more tasks to the chain
chain(*sequential_tasks)()

Celery 将透明地处理与队列相关的工作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM