簡體   English   中英

RabbitMq - pika - python - 發布時刪除消息

[英]RabbitMq - pika - python - Dropping messages when published

def get_connection_and_channel(self, connection_parameters):
    connection = pika.BlockingConnection(connection_parameters)
    channel = connection.channel()
    return (connection, channel)  


connection_parameters = pika.ConnectionParameters( server, port, virtual_host, credentials=pika.PlainCredentials(user_name, password))

connection,channel = self.get_connection_and_channel(connection_parameters)

channel.confirm_delivery()
count=0
for json_string in open(json_file, 'r'):
    result_json = json.loads(json_string)
    message_body = json.dumps(result_json['body'])
    routing_key = result_json['RoutingKey']
    channel.basic_publish(exchange=self.output_exchange_name,routing_key=routing_key,body=message_body.strip())
    count += 1
self.logger.info('Sent %d messages' % count)
connection.close()

我正在使用此代碼將消息發送到RabbitMQ服務器。 但偶爾這不會將所有消息發送到相應的隊列。 它每次運行時都會丟失隨機數量的消息。

我無法理解這里的問題是什么。

有可能是您的消息被返回,因為它無法將消息路由到任何現有隊列。 嘗試在channel.confirm_delivery添加回調:

channel.confirm_delivery(on_delivery_confirmation)

def on_delivery_confirmation(self, method_frame):
        confirmation_type = method_frame.method.NAME.split('.')[1].lower()            
        if confirmation_type == 'ack':
            self.logger.info('message published')
        elif confirmation_type == 'nack':
            self.logger.info('message not routed')

如果是這種情況,則在發布消息之前嘗試首先使用交換和路由密鑰綁定使用者隊列。

簡單(不太可靠)的方式

首先,啟用持久隊列添加:

channel.queue_declare(queue='your_queue', durable=True)

發布者和消費者 (在進行發布/消費之前)

然后,即使RabbitMQ服務器死機並重新啟動,您也可以確保您的隊列不會丟失。

出版商

在發布者上,將properties=pika.BasicProperties(delivery_mode=2)到您的basic_publish調用中,以確保您的消息是持久的。

channel.basic_publish(exchange=self.output_exchange_name,
                      routing_key=routing_key,
                      body=message_body.strip(),
                      properties=pika.BasicProperties(delivery_mode=2))

這應該可以避免丟失_published消息。

消費者

從消費者的角度來看, python官方RabbitMQ教程說:

為了確保消息永不丟失,RabbitMQ支持消息確認。 從消費者發回ack(nowledgement)以告知RabbitMQ已收到,處理了特定消息,並且RabbitMQ可以自由刪除它。 [...]默認情況下會啟用消息確認。

構建使用者時,確保正確發送ack ,讓RabbitMQ將其從隊列中刪除。

def callback(ch, method, properties, body):
    print "Received %r" % (body,)
    ch.basic_ack(delivery_tag = method.delivery_tag)

channel.basic_consume(callback, queue='your_queue')

真正安全的方式

如果您需要一種更強大,更可靠的方法來完全確定在RabbitMQ上發布確認中繼,您應該使用AMQP協議的plublish confirm功能。

來自pika文件

import pika

# Open a connection to RabbitMQ on localhost using all default parameters
connection = pika.BlockingConnection()

# Open the channel
channel = connection.channel()

# Declare the queue
channel.queue_declare(queue="test", durable=True, exclusive=False, auto_delete=False)

# Turn on delivery confirmations
channel.confirm_delivery()

# Send a message
if channel.basic_publish(exchange='test',
                         routing_key='test',
                         body='Hello World!',
                         properties=pika.BasicProperties(content_type='text/plain',
                                                         delivery_mode=1)):
    print 'Message publish was confirmed'
else:
    print 'Message could not be confirmed'

所以根據你的代碼,我將使用類似的東西:

count=0
for json_string in open(json_file, 'r'):
    result_json = json.loads(json_string)
    message_body = json.dumps(result_json['body'])
    routing_key = result_json['RoutingKey']
    if channel.basic_publish(exchange=self.output_exchange_name,routing_key=routing_key,body=message_body.strip(),
                             properties=pika.BasicProperties(delivery_mode=2)):  # Make it persistent
        count += 1
    else:
        # Do something with your undelivered message
self.logger.info('Sent %d messages' % count)
connection.close()

或者作為一種強力方法,您可以使用while循環而不是if來確保發送所有消息:

count = 0
for json_string in open(json_file, 'r'):
    result_json = json.loads(json_string)
    message_body = json.dumps(result_json['body'])
    routing_key = result_json['RoutingKey']
    while not channel.basic_publish(exchange=self.output_exchange_name,
                                    routing_key=routing_key,
                                    body=message_body.strip(),
                                    properties=pika.BasicProperties(delivery_mode=2)):
        pass # Do nothing or even you can count retries
    count += 1
self.logger.info('Sent %d messages' % count)

嘗試使用您的命令只接收一條消息:

#!/usr/bin/env python
import pika
import ujson as json


def receive():
    parameters = pika.ConnectionParameters(host='localhost')
    connection = pika.BlockingConnection(parameters)
    channel = connection.channel()
    channel.queue_declare(queue='raw_post', durable=True)

    method_frame, header_frame, body = channel.basic_get(queue='raw_post')

    if method_frame.NAME == 'Basic.GetEmpty':
        connection.close()
        return ''
    else:
        channel.basic_ack(delivery_tag=method_frame.delivery_tag)
        connection.close()
        return json.loads(body), method_frame.message_count


a = ''
while a not in ['quit', 'sair', 'exit', 'bye']:
    a = input("whats up?")
    print(receive())

只有一個發送者有5000條消息要排隊:

#!/usr/bin/env python
import pika
import ujson as json

connection = pika.BlockingConnection(pika.ConnectionParameters(host='localhost'))
channel = connection.channel()

channel.queue_declare(queue='raw_post', durable=True)

for i in range(5000):
    info = {"info": "test", "value": i}

    channel.basic_publish(exchange='',
                          routing_key='raw_post',
                          body=json.dumps(info),
                          properties=pika.BasicProperties(
                              delivery_mode=2,  # make message persistent
                          ))

    print(" [x] Sent 'Hello World!' {}".format(i))
connection.close()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM