Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/327.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python RabbitMQ、Pika和重连策略_Python_Rabbitmq_Pika - Fatal编程技术网

Python RabbitMQ、Pika和重连策略

Python RabbitMQ、Pika和重连策略,python,rabbitmq,pika,Python,Rabbitmq,Pika,我正在使用Pika处理来自RabbitMQ的数据。 由于我似乎遇到了不同类型的问题,我决定编写一个小型测试应用程序,看看如何处理断开连接 我编写了这个测试应用程序,它具有以下功能: 连接到代理,重试直到成功 连接后,创建一个队列 使用此队列并将结果放入python队列。队列(0) 从Queue.Queue(0)获取项目,并将其生成回代理队列 我注意到两个问题: 当我从一台连接到另一台主机(在vm内)上的rabbitmq的主机运行脚本时,该脚本会随机退出,而不会产生错误 当我在安装RabbitMQ

我正在使用Pika处理来自RabbitMQ的数据。 由于我似乎遇到了不同类型的问题,我决定编写一个小型测试应用程序,看看如何处理断开连接

我编写了这个测试应用程序,它具有以下功能:

  • 连接到代理,重试直到成功
  • 连接后,创建一个队列
  • 使用此队列并将结果放入python队列。队列(0)
  • 从Queue.Queue(0)获取项目,并将其生成回代理队列
  • 我注意到两个问题:

  • 当我从一台连接到另一台主机(在vm内)上的rabbitmq的主机运行脚本时,该脚本会随机退出,而不会产生错误
  • 当我在安装RabbitMQ的同一台主机上运行脚本时,它运行良好并保持运行
  • 这可能是因为网络问题,数据包被丢弃,尽管我发现连接不是很牢固

    当脚本在RabbitMQ服务器上本地运行并且我杀死RabbitMQ时,脚本退出并出现错误:“error pika SelectConnection:Socket error on 3:104”

    看来我无法让重连策略正常工作。有人能看一下代码看看我做错了什么吗

    谢谢

    杰伊


    脚本的主要问题是它与来自主线程(ioloop正在运行的地方)和“代理”线程(在循环中调用
    submitData
    )的单个通道进行交互。这是

    而且,
    SimpleConnectionStrategy
    似乎没有做任何有用的事情。如果连接中断,则不会导致重新连接。我相信这是皮卡舞中的一只虫子:


    我试图重构您的代码,使其按照我认为您希望的方式工作,但遇到了另一个问题。Pika似乎没有检测传输失败的方法,这意味着如果连接中断,数据可能会丢失。这似乎是一个如此明显的要求!怎么可能无法检测到
    basic\u publish
    失败?我尝试了各种各样的东西,包括事务和
    返回时添加回调
    (所有这些看起来都很笨重,过于复杂),但什么都没想到。如果真的没有办法,那么pika似乎只在能够容忍发送到RabbitMQ的数据丢失的情况下,或者在只需要使用RabbitMQ的程序中有用

    这是不可靠的,但作为参考,以下是一些解决多线程问题的代码:

    import logging
    import pika
    import Queue
    import sys
    import threading
    import time
    from functools import partial
    from pika.adapters import SelectConnection, BlockingConnection
    from pika.exceptions import AMQPConnectionError
    from pika.reconnection_strategies import SimpleReconnectionStrategy
    
    log = logging.getLogger(__name__)
    
    DEFAULT_PROPERTIES = pika.BasicProperties(delivery_mode=2)
    
    
    class Broker(object):
    
        def __init__(self, parameters, on_channel_open, name='broker'):
            self.parameters = parameters
            self.on_channel_open = on_channel_open
            self.name = name
    
        def connect(self, forever=False):
            name = self.name
            while True:
                try:
                    connection = SelectConnection(
                        self.parameters, self.on_connected)
                    log.debug('%s connected', name)
                except Exception:
                    if not forever:
                        raise
                    log.warning('%s cannot connect', name, exc_info=True)
                    time.sleep(10)
                    continue
    
                try:
                    connection.ioloop.start()
                finally:
                    try:
                        connection.close()
                        connection.ioloop.start() # allow connection to close
                    except Exception:
                        pass
    
                if not forever:
                    break
    
        def on_connected(self, connection):
            connection.channel(self.on_channel_open)
    
    
    def setup_submitter(channel, data_queue, properties=DEFAULT_PROPERTIES):
        def on_queue_declared(frame):
            # PROBLEM pika does not appear to have a way to detect delivery
            # failure, which means that data could be lost if the connection
            # drops...
            channel.confirm_delivery(on_delivered)
            submit_data()
    
        def on_delivered(frame):
            if frame.method.NAME in ['Confirm.SelectOk', 'Basic.Ack']:
                log.info('submission confirmed %r', frame)
                # increasing this value seems to cause a higher failure rate
                time.sleep(0)
                submit_data()
            else:
                log.warn('submission failed: %r', frame)
                #data_queue.put(...)
    
        def submit_data():
            log.info('waiting on data queue')
            data = data_queue.get()
            log.info('got data to submit')
            channel.basic_publish(exchange='',
                        routing_key='sandbox',
                        body=data,
                        properties=properties,
                        mandatory=True)
            log.info('submitted data to broker')
    
        channel.queue_declare(
            queue='sandbox', durable=True, callback=on_queue_declared)
    
    
    def blocking_submitter(parameters, data_queue,
            properties=DEFAULT_PROPERTIES):
        while True:
            try:
                connection = BlockingConnection(parameters)
                channel = connection.channel()
                channel.queue_declare(queue='sandbox', durable=True)
            except Exception:
                log.error('connection failure', exc_info=True)
                time.sleep(1)
                continue
            while True:
                log.info('waiting on data queue')
                try:
                    data = data_queue.get(timeout=1)
                except Queue.Empty:
                    try:
                        connection.process_data_events()
                    except AMQPConnectionError:
                        break
                    continue
                log.info('got data to submit')
                try:
                    channel.basic_publish(exchange='',
                                routing_key='sandbox',
                                body=data,
                                properties=properties,
                                mandatory=True)
                except Exception:
                    log.error('submission failed', exc_info=True)
                    data_queue.put(data)
                    break
                log.info('submitted data to broker')
    
    
    def setup_receiver(channel, data_queue):
        def process_data(channel, method, properties, body):
            log.info('received data from broker')
            data_queue.put(body)
            channel.basic_ack(delivery_tag=method.delivery_tag)
    
        def on_queue_declared(frame):
            channel.basic_consume(process_data, queue='sandbox')
    
        channel.queue_declare(
            queue='sandbox', durable=True, callback=on_queue_declared)
    
    
    if __name__ == '__main__':
        if len(sys.argv) != 2:
            print 'usage: %s RABBITMQ_HOST' % sys.argv[0]
            sys.exit()
    
        format=('%(asctime)s %(levelname)s %(name)s %(message)s')
        logging.basicConfig(level=logging.DEBUG, format=format)
    
        host = sys.argv[1]
        log.info('connecting to host: %s', host)
        parameters = pika.ConnectionParameters(host=host, heartbeat=True)
        data_queue = Queue.Queue(0)
        data_queue.put('message') # prime the pump
    
        # run submitter in a thread
    
        setup = partial(setup_submitter, data_queue=data_queue)
        broker = Broker(parameters, setup, 'submitter')
        thread = threading.Thread(target=
             partial(broker.connect, forever=True))
    
        # uncomment these lines to use the blocking variant of the submitter
        #thread = threading.Thread(target=
        #    partial(blocking_submitter, parameters, data_queue))
    
        thread.daemon = True
        thread.start()
    
        # run receiver in main thread
        setup = partial(setup_receiver, data_queue=data_queue)
        broker = Broker(parameters, setup, 'receiver')
        broker.connect(forever=True)
    

    感谢您花时间阅读代码并找到与之相关的所有问题。我目前使用的是一个更基本/更简单的库,但完全适合我的需要。结合gevent,我得到了一些非常好的结果。现在我不再为Pika操心了。您可以使用Channel.confirm_delivery()在发布后等待确认,一旦连接关闭,它将超时,然后您将知道消息没有传递给代理“Pika似乎没有检测传递失败的方法,这意味着如果连接断开,数据可能会丢失”-这不是真的。如果使用publisher confirms,您将知道邮件何时送达。在某一点上,我将提供显示这一点的代码,但您可以使用作为概念的示例。
    import logging
    import pika
    import Queue
    import sys
    import threading
    import time
    from functools import partial
    from pika.adapters import SelectConnection, BlockingConnection
    from pika.exceptions import AMQPConnectionError
    from pika.reconnection_strategies import SimpleReconnectionStrategy
    
    log = logging.getLogger(__name__)
    
    DEFAULT_PROPERTIES = pika.BasicProperties(delivery_mode=2)
    
    
    class Broker(object):
    
        def __init__(self, parameters, on_channel_open, name='broker'):
            self.parameters = parameters
            self.on_channel_open = on_channel_open
            self.name = name
    
        def connect(self, forever=False):
            name = self.name
            while True:
                try:
                    connection = SelectConnection(
                        self.parameters, self.on_connected)
                    log.debug('%s connected', name)
                except Exception:
                    if not forever:
                        raise
                    log.warning('%s cannot connect', name, exc_info=True)
                    time.sleep(10)
                    continue
    
                try:
                    connection.ioloop.start()
                finally:
                    try:
                        connection.close()
                        connection.ioloop.start() # allow connection to close
                    except Exception:
                        pass
    
                if not forever:
                    break
    
        def on_connected(self, connection):
            connection.channel(self.on_channel_open)
    
    
    def setup_submitter(channel, data_queue, properties=DEFAULT_PROPERTIES):
        def on_queue_declared(frame):
            # PROBLEM pika does not appear to have a way to detect delivery
            # failure, which means that data could be lost if the connection
            # drops...
            channel.confirm_delivery(on_delivered)
            submit_data()
    
        def on_delivered(frame):
            if frame.method.NAME in ['Confirm.SelectOk', 'Basic.Ack']:
                log.info('submission confirmed %r', frame)
                # increasing this value seems to cause a higher failure rate
                time.sleep(0)
                submit_data()
            else:
                log.warn('submission failed: %r', frame)
                #data_queue.put(...)
    
        def submit_data():
            log.info('waiting on data queue')
            data = data_queue.get()
            log.info('got data to submit')
            channel.basic_publish(exchange='',
                        routing_key='sandbox',
                        body=data,
                        properties=properties,
                        mandatory=True)
            log.info('submitted data to broker')
    
        channel.queue_declare(
            queue='sandbox', durable=True, callback=on_queue_declared)
    
    
    def blocking_submitter(parameters, data_queue,
            properties=DEFAULT_PROPERTIES):
        while True:
            try:
                connection = BlockingConnection(parameters)
                channel = connection.channel()
                channel.queue_declare(queue='sandbox', durable=True)
            except Exception:
                log.error('connection failure', exc_info=True)
                time.sleep(1)
                continue
            while True:
                log.info('waiting on data queue')
                try:
                    data = data_queue.get(timeout=1)
                except Queue.Empty:
                    try:
                        connection.process_data_events()
                    except AMQPConnectionError:
                        break
                    continue
                log.info('got data to submit')
                try:
                    channel.basic_publish(exchange='',
                                routing_key='sandbox',
                                body=data,
                                properties=properties,
                                mandatory=True)
                except Exception:
                    log.error('submission failed', exc_info=True)
                    data_queue.put(data)
                    break
                log.info('submitted data to broker')
    
    
    def setup_receiver(channel, data_queue):
        def process_data(channel, method, properties, body):
            log.info('received data from broker')
            data_queue.put(body)
            channel.basic_ack(delivery_tag=method.delivery_tag)
    
        def on_queue_declared(frame):
            channel.basic_consume(process_data, queue='sandbox')
    
        channel.queue_declare(
            queue='sandbox', durable=True, callback=on_queue_declared)
    
    
    if __name__ == '__main__':
        if len(sys.argv) != 2:
            print 'usage: %s RABBITMQ_HOST' % sys.argv[0]
            sys.exit()
    
        format=('%(asctime)s %(levelname)s %(name)s %(message)s')
        logging.basicConfig(level=logging.DEBUG, format=format)
    
        host = sys.argv[1]
        log.info('connecting to host: %s', host)
        parameters = pika.ConnectionParameters(host=host, heartbeat=True)
        data_queue = Queue.Queue(0)
        data_queue.put('message') # prime the pump
    
        # run submitter in a thread
    
        setup = partial(setup_submitter, data_queue=data_queue)
        broker = Broker(parameters, setup, 'submitter')
        thread = threading.Thread(target=
             partial(broker.connect, forever=True))
    
        # uncomment these lines to use the blocking variant of the submitter
        #thread = threading.Thread(target=
        #    partial(blocking_submitter, parameters, data_queue))
    
        thread.daemon = True
        thread.start()
    
        # run receiver in main thread
        setup = partial(setup_receiver, data_queue=data_queue)
        broker = Broker(parameters, setup, 'receiver')
        broker.connect(forever=True)