RabbitMQ在使用者重新连接前丢失消息
我实现了一个使用者,如果底层连接关闭,它将在一段时间后自动重新连接到代理。我的情况如下:RabbitMQ在使用者重新连接前丢失消息,rabbitmq,amqp,Rabbitmq,Amqp,我实现了一个使用者,如果底层连接关闭,它将在一段时间后自动重新连接到代理。我的情况如下: @Override public void consume(final String exchangeName, final String queueName, final String routingKey, final int qos) throws IOException, InterruptedException { ConnectionFactory factory
@Override
public void consume(final String exchangeName, final String queueName, final String routingKey,
final int qos) throws IOException, InterruptedException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost(this.getHost());
while (true) {
Connection connection = null;
try {
connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare(exchangeName, "topic");
// declare a durable, non-exclusive, non-autodelete queue.
channel.queueDeclare(queueName, true, false, false, null);
channel.queueBind(queueName, exchangeName, routingKey);
// distribute workload among all consumers, consumer will
// pre-fetch
// {qos}
// messages to local buffer.
channel.basicQos(qos);
logger.debug(" [*] Waiting for messages. To exit press CTRL+C");
QueueingConsumer consumer = new QueueingConsumer(channel);
// disable auto-ack. If enable auto-ack, RabbitMQ delivers a
// message to
// the customer it immediately removes it from memory.
boolean autoAck = false;
channel.basicConsume(queueName, autoAck, consumer);
while (true) {
QueueingConsumer.Delivery delivery = consumer.nextDelivery();
try {
RabbitMessageConsumer.this.consumeMessage(delivery);
}
catch (Exception e) {
// the exception shouldn't affect the next message
logger.info("[IGNORE]" + e.getMessage());
}
channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
}
}
catch (Exception e) {
logger.warn(e);
}
if (autoReconnect) {
this.releaseConn(connection);
logger.info("[*] Will try to reconnect to remote host(" + this.getHost() + ") in "
+ this.reconnectInterval / 1000 + " seconds.");
Thread.sleep(this.getReconnectInterval());
}
else
break;
}
}
private void releaseConn(Connection conn) {
try {
if (conn != null)
conn.close();
}
catch (Exception e) {
// simply ignore this exception
}
}
ConnectionFactory factory = new ConnectionFactory();
factory.setHost(this.getHost());
connection = factory.newConnection();
Channel channel = connection.createChannel();
channel = conn.createChannel();
// declare a 'topic' type of exchange
channel.exchangeDeclare(exchangeName, "topic");
// Content-type "application/octet-stream", deliveryMode 2
// (persistent), priority zero
channel.basicPublish(exchangeName, routingKey, MessageProperties.PERSISTENT_BASIC, message);
connection.close();
消费者信息如下:
@Override
public void consume(final String exchangeName, final String queueName, final String routingKey,
final int qos) throws IOException, InterruptedException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost(this.getHost());
while (true) {
Connection connection = null;
try {
connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare(exchangeName, "topic");
// declare a durable, non-exclusive, non-autodelete queue.
channel.queueDeclare(queueName, true, false, false, null);
channel.queueBind(queueName, exchangeName, routingKey);
// distribute workload among all consumers, consumer will
// pre-fetch
// {qos}
// messages to local buffer.
channel.basicQos(qos);
logger.debug(" [*] Waiting for messages. To exit press CTRL+C");
QueueingConsumer consumer = new QueueingConsumer(channel);
// disable auto-ack. If enable auto-ack, RabbitMQ delivers a
// message to
// the customer it immediately removes it from memory.
boolean autoAck = false;
channel.basicConsume(queueName, autoAck, consumer);
while (true) {
QueueingConsumer.Delivery delivery = consumer.nextDelivery();
try {
RabbitMessageConsumer.this.consumeMessage(delivery);
}
catch (Exception e) {
// the exception shouldn't affect the next message
logger.info("[IGNORE]" + e.getMessage());
}
channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
}
}
catch (Exception e) {
logger.warn(e);
}
if (autoReconnect) {
this.releaseConn(connection);
logger.info("[*] Will try to reconnect to remote host(" + this.getHost() + ") in "
+ this.reconnectInterval / 1000 + " seconds.");
Thread.sleep(this.getReconnectInterval());
}
else
break;
}
}
private void releaseConn(Connection conn) {
try {
if (conn != null)
conn.close();
}
catch (Exception e) {
// simply ignore this exception
}
}
由于它是一个“主题”交换,所以在发布服务器上没有声明队列。但是,在第1个测试的步骤#3,已声明持久队列,并且消息也是持久的。我不明白为什么重新连接之前会丢失消息。如果发布时没有队列,消息将丢失。您是否连接到同一队列(如果是),它是否持久,还是在重新启动RMQ服务器后发布消息之前重新创建它?听起来解决方案是:
此外,请确保您正在重新连接到消费者中的正确队列。1) 可能是两种解决方案中更好的一种。哦,我找到了原因……消息和队列当然是持久的,但是交换不是持久的。由于交换不持久,队列和交换之间的绑定信息将在RabbitMQ代理重新启动之间丢失
现在,我将exchange声明为持久的,使用者可以在使用者重新启动之前和代理重新启动之后获得发布的消息。在我从3.1升级到3.3之后,我的RabbitMQ集群会发生这种情况。我的解决方案是删除
/var/lib/rabbitmq/mnesia
目录 而不是channel.queueDeclare(队列名称,true,false,false,null)代码>
使用这个channel.queueDeclare(队列名称,false,false,null)代码>
重新启动RabbitMQ后,队列是否存在?它是否绑定到要将邮件发布到的exchange?是的,队列是持久的。在第二次测试中,在重新启动rabbitMQ代理后,使用者成功接收到消息。在重新启动rabbitMQ服务器之后和使用者重新连接之前,“list_queues”命令的结果是“Listing queues…com.mpos.lotket.te.thirdpartyservice.amqp.RabbitMessagePublisher 0…done”。这是使用者声明的队列。