RabbitMQ阻塞读取时数据时,关闭channel引起的问题和解决方案

本文探讨了在RabbitMQ中优雅地关闭消费者的几种方法,避免了直接关闭channel导致的异常问题。通过设置超时时间并改变读取消息的方式,实现了更加平滑的关闭过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

项目场景:

  最近在项目中使用了RabbitMq,其中有一个功能必须能随时切断RabbitMq的coumser。第一时间写出来的代码如下:

  伪代码:
 1 while(flag){
 2     
 3      QueueingConsumer.Delivery delivery=consumer.nextDelivery();
 4      String message = new String(delivery.getBody());
 5      //doing someting strange
 6      //...... 
 7 
 8 }
 9 
10 
11 //另外一个项目开始关闭
12 
13 public void closeConsumer{
14       channel().close();
15       connection().close();
16 }
17 closeConsumer();

 通过关闭channel,消费者自然会关闭。然而,项目开始报错:

 

channel关闭抛出ShutdownSignalException,抛出异常就表示这种关闭方式是不合理的。有必要去探索一下是否有更优雅的链接关闭方式。

 

先看consumer的源码:

public Delivery nextDelivery()throws InterruptedException, ShutdownSignalException, ConsumerCancelledException{
     return handle(_queue.take());
 }

而这里_queue其实是一个 LinkedBlockingQueue,LinkedBlockingQueue是一个单向链表实现的阻塞队列。nextDelivery()方法使用LinkedBlockingQueue的take方法实现了阻塞。这个地方感觉不好操作。但是QueueingConsumer还有另外一个读取数据的方法,源码如下:

public Delivery nextDelivery(long timeout)throws InterruptedException, ShutdownSignalException, ConsumerCancelledException{
       return handle(_queue.poll(timeout, TimeUnit.MILLISECONDS));
}

这边设定了超时时间。虽然没想到优雅关闭消费者的方法,但是利用超时时间来修改一下读取数据的方法还是可以的。代码如下:

try{
    while(flag){
         QueueingConsumer.Delivery delivery = consumer.getDeliveryMessage(10000);
         if(consumer.getState()==Consumer.Status.Stopped.getValue()){
              break;
         }
         if(delivery==null){
                  continue;
         }
      String message = new String(delivery.getBody());
       //....dosomething
    }
}finally {
    if(consumer!=null){
        consumer.closeConnection();
    }
}


public void closeConnection{  
  channel().close();  
  connection().close(); 
}

//另外一个线程关闭consumer
consumer.setStatus(Consumer.Status.Stopped);

 

 总结:这种关闭方式可以让Mq关闭连接时不抛出异常,比之前的方式好一点。但可能并不是最好的方法。如果有更好的方案,请留言告诉我,谢谢

 

转载于:https://www.cnblogs.com/null-qige/p/8145094.html

在C#中,消费者消费RabbitMQ消息的过程通常涉及到使用RabbitMQ.Client这个库。RabbitMQ.Client提供了.NET环境下与RabbitMQ服务器交互的API。一个消费者读取消息后可能会断开连接的原因可能是为了节省资源或者根据特定的应用逻辑。下面是一个简化的示例,介绍如何使用RabbitMQ.Client在C#中创建消费者、接收消息,并在读取消息后关闭连接。 ```csharp using RabbitMQ.Client; using RabbitMQ.Client.Events; using System; class Program { static void Main() { // 创建连接工厂,设置RabbitMQ服务器的地址 var factory = new ConnectionFactory() { HostName = "localhost" }; // 创建连接,并且打开连接到RabbitMQ服务器 using (var connection = factory.CreateConnection()) using (var channel = connection.CreateModel()) { // 声明队列,如果队列不存在则创建 channel.QueueDeclare(queue: "hello", durable: false, exclusive: false, autoDelete: false, arguments: null); // 创建消费者 var consumer = new EventingBasicConsumer(channel); // 接收消息的回调函数 consumer.Received += (model, ea) => { var body = ea.Body.ToArray(); var message = System.Text.Encoding.UTF8.GetString(body); Console.WriteLine(" [x] Received {0}", message); // 执行完业务逻辑后,关闭连接 channel.Close(); connection.Close(); }; // 开始接收消息 channel.BasicConsume(queue: "hello", autoAck: true, consumer: consumer); // 阻塞主线程,防止程序退出 Console.WriteLine(" Press [enter] to exit."); Console.ReadLine(); } } } ``` 在这个例子中,我们首先创建了连接工厂,并指定了RabbitMQ服务器的地址。然后,我们创建了一个连接,并从这个连接中打开一个通道。我们声明了一个队列,并创建了一个消费者来监听这个队列的消息。当消费者接收到消息,它会处理消息并打印到控制台,然后关闭通道连接。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值