Python 使用芹菜将消息发布到RabbitMQ中的Exchange
我已经编写了一个Django项目,它通过Python 使用芹菜将消息发布到RabbitMQ中的Exchange,python,django,rabbitmq,celery,django-celery,Python,Django,Rabbitmq,Celery,Django Celery,我已经编写了一个Django项目,它通过my_task.delay()异步提示不同的任务。问题是,随着项目规模越来越大,很难正确地路由任务——我开始编写任务,其唯一目的是组合不同的任务,这使得代码在一段时间后变得混乱 在阅读一些RabbitMQ文档时,我想到了一个解决方案,它可以更好地构建依赖于交换的项目。Exchange可以将邮件发布到多个队列,消费者可以在这些队列上使用邮件,简言之: 描述了一个使用Pika的解决方案,Pika是RabbitMQ比芹菜更低级的客户端 芹菜文档在其中描述了此场
my_task.delay()
异步提示不同的任务。问题是,随着项目规模越来越大,很难正确地路由任务——我开始编写任务,其唯一目的是组合不同的任务,这使得代码在一段时间后变得混乱
在阅读一些RabbitMQ文档时,我想到了一个解决方案,它可以更好地构建依赖于交换的项目。Exchange可以将邮件发布到多个队列,消费者可以在这些队列上使用邮件,简言之:
描述了一个使用Pika的解决方案,Pika是RabbitMQ比芹菜更低级的客户端
芹菜文档在其中描述了此场景,但没有描述如何创建一个生产者,该生产者生成消息,这些消息被发送到一个将其分发到各种队列的交换机,如上图所示。
它只描述了如何处理消息队列和-但我希望由Exchange处理
我发现芹菜所依赖的Kombu有一个功能,可以通过a向交换机发送消息,但我找不到任何文档说明如何在芹菜django中使用它
我怎样才能在芹菜中归档所描述的程序
PS:已经有一个关于StackOverflow的建议,建议使用诸如Chain和Group of芹菜之类的原语,但这与我理解的交换范式相矛盾。要获得良好的任务路由,您应该创建更多的队列。芹菜使用单个交换,并直接绑定到队列。通过设置多个队列,您可以拆分工作。然后,您可以启动更多只使用特定队列的工人,以更快地处理工作量最大的队列 看看Sentry是如何解决这个问题的: 此外,如果您确实想使用多个交换机,您可以在设置文件中设置更多的交换机,并在任务队列上定义在哪个路由上使用哪个交换机。保持直接交换芹菜,如果需要,你可以转投其他经纪人
first_exchange = kombu.Exchange(name="first", type="direct")
second_exchange = kombu.Exchange(name="second", type="direct")
task_queues = [
kombu.Queue(
name="queue1",
exchange=first_exchange,
routing_key="queue1",
),
kombu.Queue(
name="queue2",
exchange=second_exchange,
routing_key="queue2",
)]
当我试图解决将邮件从芹菜任务发送到芹菜不使用的另一个交换时,我多次遇到这个问题。我想我会分享我的研究结果,以防其他人提出同样的问题
这是使用芹菜4.3,而不是django不再需要的django芹菜
我有一个django应用程序,除了使用芹菜之外,它还通过RabbitMQ向其他较小的集成应用程序和客户发送“常规”AMQP消息
因此,在芹菜任务中,我想将邮件发送到一个与我用于芹菜任务的交换机不同的交换机,并且邮件不是任务
我最初的解决方案就是在每个任务中创建一个新的连接。但我认为这不是那么可扩展,因为如果我的应用程序处理大量并发任务,我将获得大量连接。在我需要新连接的地方,为我的amqp连接字符串导入django设置也很烦人
相反,我开始研究是否可以以某种方式从芹菜中获取当前连接并重用它以发布到RabbitMQ。最好像我在非django消费者和生产者中所做的那样使用连接池
事实证明,连接池和prodcucer池很容易获得
在celery.py中初始设置我的外部消息:
app = Celery("my_proj")
setting_object = import_module(settings.CELERY_CONF_MODULE)
app.config_from_object(setting_object)
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
with app.pool.acquire(block=True) as conn:
exchange = kombu.Exchange(
name=settings.AMQP_PUBLISH_TO, type="topic", durable=True, channel=conn
)
exchange.declare()
queue = kombu.Queue(
name="my_queue",
exchange=exchange,
routing_key="my_queue.#",
channel=conn,
)
queue.declare()
在我的芹菜任务中,我使用当前的_应用程序,因为它是在workers上运行的
@task
def my_task(attrs):
# do something
with current_app.producer_pool.acquire(block=True) as producer:
producer.publish(
body,
routing_key="my_queue.test",
exchange=settings.AMQP_PUBLISH_TO,
retry=True,
)
这对我来说真的很好。但你不可能总是渴望得到芹菜。我在这方面遇到了问题,因为当时没有真正使用连接。所以我的测试需要写得更好一点,但没关系