Python 使用Tornado和Pika进行异步队列监控

Python 使用Tornado和Pika进行异步队列监控,python,asynchronous,rabbitmq,amqp,tornado,Python,Asynchronous,Rabbitmq,Amqp,Tornado,我有一个AMQP服务器(),我想在一个数据库中发布和读取它。为此,我想我应该使用一个异步amqp python库;特别是(它的一个变种,据说支持龙卷风) 我编写的代码似乎成功地从队列中读取,只是在请求结束时出现异常(浏览器返回正常): 我不完全确定我是否正确使用了这个库,所以我可能做了一些明显错误的事情。我的代码的基本流程是: 请求进来了 使用TornadConnection创建到RabbitMQ的连接;指定一个回调 在连接回调中,创建通道,声明/绑定我的队列,调用basic_consume;指

我有一个AMQP服务器(),我想在一个数据库中发布和读取它。为此,我想我应该使用一个异步amqp python库;特别是(它的一个变种,据说支持龙卷风)

我编写的代码似乎成功地从队列中读取,只是在请求结束时出现异常(浏览器返回正常):

我不完全确定我是否正确使用了这个库,所以我可能做了一些明显错误的事情。我的代码的基本流程是:

  • 请求进来了
  • 使用TornadConnection创建到RabbitMQ的连接;指定一个回调
  • 在连接回调中,创建通道,声明/绑定我的队列,调用basic_consume;指定一个回调
  • 在consume回调中,关闭通道并调用Tornado的finish函数
  • 见例外
  • 我的问题是:

  • 这个流程是否正确?我不确定连接回调的目的是什么,只是如果我不使用它,它就不起作用
  • 我应该为每个web请求创建一个AMQP连接吗?RabbitMQ的文档表明,不,我不应该,而是应该坚持只创建通道。但是,我将在哪里创建连接,如果连接短暂中断,我将如何尝试重新连接
  • 如果我为每个Web请求创建一个AMQP连接,我应该在哪里关闭它?在回调中调用amqp.close()似乎会把事情搞得更糟

  • 稍后我将尝试编写一些示例代码,但上面描述的步骤相当完整地展示了事物的消费方面。我在出版方面也遇到了一些问题,但排队的问题更为紧迫。

    有人报告说,Tornado和Pika成功合并。据我所知,这并不像从Tornado调用Pika那样简单,因为两个库都希望有自己的事件循环负责。

    查看一些源代码会有所帮助,但我在多个生产项目中使用了相同的Tornado支持Pika模块,没有问题

    您不想为每个请求创建连接。创建一个封装所有AMQP操作的类,并在tornado应用程序级别将其实例化为可跨请求(以及跨请求处理程序)使用的单例。我在一个“runapp()”函数中这样做,该函数执行类似的操作,然后启动主tornado ioloop

    这里有一个叫做“事件”的类。这是一个部分实现(具体来说,我在这里不定义“self.handle\u事件”。这取决于您

    class Event(object):
      def __init__(self, config):
        self.host = 'localhost'
        self.port = '5672'
        self.vhost = '/'
        self.user = 'foo'
        self.exchange = 'myx'
        self.queue = 'myq'
        self.recv_routing_key = 'msgs4me'
        self.passwd = 'bar'
    
        self.connected = False 
        self.connect()
    
    
      def connect(self):
    
        credentials = pika.PlainCredentials(self.user, self.passwd)
    
        parameters = pika.ConnectionParameters(host = self.host,
                                             port = self.port,
                                             virtual_host = self.vhost,
                                             credentials = credentials)
    
        srs = pika.connection.SimpleReconnectionStrategy()
    
        logging.debug('Events: Connecting to AMQP Broker: %s:%i' % (self.host,
                                                                  self.port))
        self.connection = tornado_adapter.TornadoConnection(parameters,
                                                          wait_for_open = False,
                                                          reconnection_strategy = srs,
                                                          callback = self.on_connected)
    
      def on_connected(self):
    
        # Open the channel
        logging.debug("Events: Opening a channel")
        self.channel = self.connection.channel()
    
        # Declare our exchange
        logging.debug("Events: Declaring the %s exchange" %  self.exchange)
        self.channel.exchange_declare(exchange = self.exchange,
                                    type = "fanout",
                                    auto_delete = False,
                                    durable = True)
    
        # Declare our queue for this process
        logging.debug("Events: Declaring the %s queue" %  self.queue)
        self.channel.queue_declare(queue = self.queue,
                                 auto_delete = False,
                                 exclusive = False,
                                 durable = True)
    
    
        # Bind to the exchange
        self.channel.queue_bind(exchange = self.exchange,
                              queue = self.queue,
                              routing_key = self.recv_routing_key)
    
        self.channel.basic_consume(consumer = self.handle_event, queue = self.queue, no_ack = True)
    
        # We should be connected if we made it this far
        self.connected = True
    
    然后我把它放在一个名为“events.py”的文件中。我的RequestHandler和任何后端代码都使用一个“common.py”模块,该模块封装了对两者都有用的代码(我的RequestHandler不直接调用任何amqp模块方法——对于db、缓存等也是如此),因此我在common.py中的模块级别定义了“events=None”,并实例化了事件对象,如下所示:

    import events
    
    def runapp(config):
        if myapp.common.events is None: 
           myapp.common.events = myapp.events.Event(config)
        logging.debug("MYAPP.COMMON.EVENTS: %s", myapp.common.events)
        http_server = tornado.httpserver.HTTPServer(app,
                                                xheaders=config['HTTPServer']['xheaders'],
                                                no_keep_alive=config['HTTPServer']['no_keep_alive'])
        http_server.listen(port) 
        main_loop = tornado.ioloop.IOLoop.instance()
        logging.debug("MAIN IOLOOP: %s", main_loop)
        main_loop.start()
    

    新年快乐:-D

    看到代码本身要比阅读口头解释好得多。是的,我使用的是专门支持Tornado的Pika变体。我想我已经解决了所有问题。如果我有信心,我稍后会发布解决方案。
    import events
    
    def runapp(config):
        if myapp.common.events is None: 
           myapp.common.events = myapp.events.Event(config)
        logging.debug("MYAPP.COMMON.EVENTS: %s", myapp.common.events)
        http_server = tornado.httpserver.HTTPServer(app,
                                                xheaders=config['HTTPServer']['xheaders'],
                                                no_keep_alive=config['HTTPServer']['no_keep_alive'])
        http_server.listen(port) 
        main_loop = tornado.ioloop.IOLoop.instance()
        logging.debug("MAIN IOLOOP: %s", main_loop)
        main_loop.start()