Django:如何建立与rabbitmq的持久连接?

时间:2019-03-14 01:21:53

标签: django docker rabbitmq amqp pika

我正在寻找一种从Django应用程序将消息发布到Rabbitmq服务器的方法。这不是用于任务卸载,因此我不想使用Celery。目的是使用django应用程序发布到交易所,并在Docker容器中从该队列中使用一个姐妹(非django)应用程序。

这一切看起来非常简单,但是,即使没有明确要求发生这种情况,我也似乎无法在每次都没有建立和关闭连接的情况下发布到交易所。

为了解决这个问题,我定义了一个带有嵌套单例类的类,该类维护使用Pika到Rabbitmq服务器的连接。想法是嵌套的单例仅实例化一次,此时声明连接。任何时候只要有东西要发布到队列中,单例都会处理它。

import logging
import pika
import os

logger = logging.getLogger('django')

class PikaChannelSingleton:
    class __Singleton:
        channel = pika.adapters.blocking_connection.BlockingChannel

        def __init__(self):
            self.initialize_connection()

        def initialize_connection(self):
            logger.info('Attempting to establish RabbitMQ connection')

            credentials = pika.PlainCredentials(rmq_username, rmq_password)
            parameters = pika.ConnectionParameters(rmq_host, rmq_port, rmq_vhost, credentials, heartbeat=0)
            connection = pika.BlockingConnection(parameters)

            con_chan = connection.channel()
            con_chan.exchange_declare(exchange='xchng', exchange_type='topic', durable=True)
            self.channel = con_chan

        def send(self, routing_key, message):
            if self.channel.is_closed:
                PikaChannelSingleton.instance.initialize_connection()

            self.channel.basic_publish(exchange='xchng', routing_key=routing_key,
                                                                body=message)
    instance = None

    def __init__(self, *args, **kwargs):
        if not PikaChannelSingleton.instance:
            logger.info('Creating channel singleton')
            PikaChannelSingleton.instance = PikaChannelSingleton.__Singleton()

    @staticmethod
    def send(routing_key, message):
        PikaChannelSingleton.instance.send(routing_key, message)

rmq_connection = PikaChannelSingleton()

然后在Django应用程序中需要的地方导入rmq_connection。一切都可以在玩具应用程序和python repl中运行,但是每次在django应用程序中调用send函数时,都会建立一个新的连接。然后,连接立即关闭,并显示消息“客户端意外关闭TCP连接”。邮件确实正确地发布到了交易所。

因此,我敢肯定django会发生一些事情,以及它如何处理进程等。问题仍然存在,如何在不每次都重新建立连接的情况下将大量消息发布到队列中?

1 个答案:

答案 0 :(得分:0)

如果我正确理解,连接将无法像在单线程上下文中那样保持活动状态。随着您的Django应用继续执行,amqp客户端未在通道上发送heartbeats,连接将终止。

您可以使用SelectConnection instead of BlockingConnection,在Django的上下文中可能并不容易。

一个不错的折衷方案是只在您的单例中收集消息,而仅在Django请求结束时使用BlockingConnection一次发送所有消息。