Django 如何在运行时创建芹菜队列,以便发送到该队列的任务被工作人员拾取?

Django 如何在运行时创建芹菜队列,以便发送到该队列的任务被工作人员拾取?,django,queue,celery,amqp,worker,Django,Queue,Celery,Amqp,Worker,我使用的是django 1.4、芹菜3.0和rabbitmq 为了描述这个问题,我在一个系统中有许多内容网络,我需要一个队列来处理与这些网络中的每一个相关的任务 但是,内容是在系统处于活动状态时动态创建的,因此我需要动态创建队列,并让现有工作人员开始处理这些队列 我尝试了以下方式安排任务(其中内容是django模型实例): queue_name='content.{}'。格式(content.pk) #例如,队列名称=content.0c3a92a4-3472-47b8-8258-2d6c8a7

我使用的是django 1.4、芹菜3.0和rabbitmq

为了描述这个问题,我在一个系统中有许多内容网络,我需要一个队列来处理与这些网络中的每一个相关的任务

但是,内容是在系统处于活动状态时动态创建的,因此我需要动态创建队列,并让现有工作人员开始处理这些队列

我尝试了以下方式安排任务(其中内容是django模型实例):

queue_name='content.{}'。格式(content.pk)
#例如,队列名称=content.0c3a92a4-3472-47b8-8258-2d6c8a71e3ba
添加内容。应用异步(args=[content],queue=queue\u name)
这将创建一个名为
内容的队列。0c3a92a4-3472-47b8-8258-2d6c8a71e3ba
,创建一个名为
内容的新交换。0c3a92a4-3472-47b8-8258-2d6c8a71e3ba
和路由键
内容。0c3a92a4-3472-47b8-8258-2d6c8a71e3ba
,并向该队列发送任务

但是,我从来没有看到工作人员执行这些任务。我当前设置的工作人员没有监听任何特定队列(没有使用队列名称初始化),只接收发送到默认队列的任务。我的芹菜是:

BROKER\u URL=”amqp://test:password@本地主机:5672/vhost“
芹菜时区='UTC'
芹菜总是渴望=错误
从kombu导入交换,队列
芹菜\默认\队列='默认'
芹菜\默认\交换='默认'
芹菜\默认\交换\类型='直接'
芹菜\默认\路由\键='默认'
芹菜(
队列(芹菜默认队列,交换(芹菜默认交换),
路由键=芹菜(默认路由键),
)
芹菜\u创建\u缺少\u队列=真
CELERYD_预取_乘数=1

您知道如何让工作人员接收发送到此新创建队列的任务吗?

您需要告诉工作人员开始使用新队列。相关文件如下所示

从命令行:

$ celery control add_consumer content.0c3a92a4-3472-47b8-8258-2d6c8a71e3ba
或者从python内部:

>>> app.control.add_consumer('content.0c3a92a4-3472-47b8-8258-2d6c8a71e3ba', reply=True)

这两种表单都接受一个destination参数,因此,如果需要,您可以只告诉单个工作人员有关新队列的信息。

我们可以动态添加队列并将工作人员附加到它们

from celery import current_app as app
from task import celeryconfig #your celeryconfig module
动态定义任务并将其路由到队列中

from task import process_data
process_data.apply_async(args,kwargs={}, queue='queue-name')
reply = app.control.add_consumer('queue_name', destination = ('your-worker-name',), reply = True)
您必须将队列名称保存在像redis这样的持久数据存储中,以便在它重新启动时能够记住它

redis.sadd('CELERY_QUEUES','queue_name')
celeryconfig.py也使用相同的方法来保持队列名称的记忆

CELERY_QUEUES = {
    'celery-1': {
        'binding_key': 'celery-1'
    },
    'gateway-1': {
        'binding_key': 'gateway-1'
    },
    'gateway-2': {
        'binding_key': 'gateway-2'
    }
}
for queue in redis.smembers('CELERY_QUEUES'):
        CELERY_QUEUES[queue] = dict(binding_key=queue)

为什么不使用一个队列并将
content.pk
作为参数传递?创建新队列的额外好处是什么?可能的额外好处是:能够在需要时为接收大量流量的内容网络增加专门的工作人员。也用于统计和日志封装等。尽管@EWit建议,我还是坚持使用默认队列机制,除非您有充分的理由将作业划分给不同的工作人员。add_consumer调用不是“粘性的”——如果重新启动工作进程,则必须重新应用队列订阅。谢谢Gavin。我现在正在检查add_consumer方法。我会让你知道我是否能让它工作。很好,这工作!非常感谢,加文。重新创建队列不是问题,因为如果需要,它们总是动态创建的。不客气。我只想从我之前的评论中强调,如果重新启动工作程序(例如,当代码更改或服务器重新启动时),它将只开始使用默认队列。每次启动工人时,您都必须添加消费者。