RabbitMQ pika losses connection

Viewed 183

I am working in a project for fun but I have been past two weeks stuck at same issue. The scenario is the following:

  1. One consumer. Each time it receives a message, it sends a GET request to an API. This requests takes less than a second.
  2. Publisher. This script is in a loop looking for changes, when it detects a change it sends and message to consumer.

Issue: This works for a few minutes.. then next time publisher wants to send a message it crashes with following error:

pika.exceptions.StreamLostError: Stream connection lost: ConnectionResetError(104, 'Connection reset by peer')

I troubleshoot a lot and but cant find the problem and fix it. I read a lot about heartbeats, but my do_work function in consumer is really quick (less than a second) so should not be the issue. Publisher, after it starts the connection goes in an infinite loop checking an api to detect changes, so maybe here is the issue? (heartbeats not being send in publisher?). I am really lost so any help will be welcome and appreciated. Thanks in advance!

publisher.py

    class BasicPikaClient:

    def __init__(self, rabbitmq_broker_id, rabbitmq_user, rabbitmq_password, region):

        # SSL Context for TLS configuration of Amazon MQ for RabbitMQ
        ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
        ssl_context.set_ciphers('ECDHE+AESGCM:!ECDSA')

        url = f"amqps://{rabbitmq_user}:{rabbitmq_password}@{rabbitmq_broker_id}.mq.{region}.amazonaws.com:5671"
        parameters = pika.URLParameters(url)
        parameters.ssl_options = pika.SSLOptions(context=ssl_context)

        self.connection = pika.BlockingConnection(parameters)
        self.channel = self.connection.channel()

        self.channel.exchange_declare(exchange='bot2', exchange_type='topic', durable=True, auto_delete=False)


class BasicMessageSender(BasicPikaClient):

    def declare_queue(self, queue_name):
        print(f"Trying to declare queue({queue_name})...")
        self.channel.queue_declare(queue=queue_name)

    def send_message(self, exchange, routing_key, body):
        channel = self.connection.channel()
        channel.basic_publish(exchange=exchange,
                              routing_key=routing_key,
                              body=body)
        print(f"Sent message. Exchange: {exchange}, Routing Key: {routing_key}, Body: {body}")

    def close(self):
        self.channel.close()
        self.connection.close()

    def pika_sleep(self,num):
        self.connection.sleep(num)



def check_stuff():
    print("do stuff")
    # here I check some api if I detect changes I send a message:
    if changes:
        basic_message_sender.send_message(exchange="bot2", routing_key="test.test", body=json_data)


def main():
    global basic_message_sender
    # Initialize Basic Message Sender which creates a connection
    # and channel for sending messages.
    basic_message_sender = BasicMessageSender(
        "host",
        "admin",
        "password",
        "region"
    )

    i = 0
    while True:
        time.sleep(0.2)
        check_stuff()

    # Close connections.
    basic_message_sender.close()

if __name__ == "__main__":
    main()

consumer.py

class BasicPikaClient:

    def __init__(self, rabbitmq_broker_id, rabbitmq_user, rabbitmq_password, region):

        # SSL Context for TLS configuration of Amazon MQ for RabbitMQ
        ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
        ssl_context.set_ciphers('ECDHE+AESGCM:!ECDSA')

        url = f"amqps://{rabbitmq_user}:{rabbitmq_password}@{rabbitmq_broker_id}.mq.{region}.amazonaws.com:5671"
        parameters = pika.URLParameters(url)
        parameters.ssl_options = pika.SSLOptions(context=ssl_context)
        parameters.heartbeat = 0

        self.connection = pika.BlockingConnection(parameters)
        self.channel = self.connection.channel()

        self.channel.exchange_declare(exchange='bot2', exchange_type='topic', durable=True, auto_delete=False)

        result = self.channel.queue_declare('', exclusive=True)
        self.queue_name = result.method.queue
        self.channel.queue_bind(exchange="bot2", queue=self.queue_name, routing_key="test.test")

def process(json_data):
    print("do GET requests")



class BasicMessageReceiver(BasicPikaClient):

    def get_message(self, queue):
        method_frame, header_frame, body = self.channel.basic_get(queue)
        if method_frame:
            print(method_frame, header_frame, body)
            self.channel.basic_ack(method_frame.delivery_tag)
            return method_frame, header_frame, body
        else:
            print('No message returned')

    def close(self):
        self.channel.close()
        self.connection.close()

    def consume_messages(self):
        def callback(ch, method, properties, body):
            print(" [x] Received %r" % body)
            process(body)

        self.channel.basic_consume(queue=self.queue_name, on_message_callback=callback, auto_ack=True)

        print(' [*] Waiting for messages. To exit press CTRL+C')
        self.channel.start_consuming()


if __name__ == "__main__":
    # Create Basic Message Receiver which creates a connection
    # and channel for consuming messages.
    basic_message_receiver = BasicMessageReceiver(
        "host",
        "user",
        "password",
        "region"
    )

    # Consume the message that was sent.
    basic_message_receiver.consume_messages()

    # Close connections.
    basic_message_receiver.close()
1 Answers

Don't know if you managed to solve this but it could be a timeout issue.

RabbitMQ has a default of 30 minutes.

If you have time.sleep() in your code it can also cause the timeout error as well. See thread

Related