为什么我的RabbitMQ频道继续关闭?

为什么我的RabbitMQ频道继续关闭?

问题描述:

我正在调试一些使用Apache POI从Microsoft Office文档中提取数据的Java代码。偶尔,它遇到一个大型文档,并且POI在内存不足时会崩溃。此时,它会尝试将错误发布到RabbitMQ,以便其他组件可以知道此步骤失败并采取适当的操作。但是,当它尝试发布到队列时,它会得到com.rabbitmq.client.AlreadyClosedException (clean connection shutdown; reason: Attempt to use closed channel)为什么我的RabbitMQ频道继续关闭?

这里的错误处理代码:

try { 
    //Extraction and indexing code 
} 
catch(Throwable t) { 
    // Something went wrong! We'll publish the error and then move on with 
    // our lives 
    System.out.println("Error received when indexing message: "); 
    t.printStackTrace(); 
    System.out.println(); 
    String error = PrintExc.format(t); 
    message.put("error", error); 

    if(mime == null) { 
     mime = "application/vnd.unknown"; 
    } 

    message.put("mime", mime); 
    publish("IndexFailure", "", MessageProperties.PERSISTENT_BASIC, message); 
} 

为了完整起见,这里的发布方法:

private void publish(String exch, String route, 
    AMQP.BasicProperties props, Map<String, Object> message) throws Exception{ 
    chan.basicPublish(exch, route, props, 
     JSONValue.toJSONString(message).getBytes()); 
} 

我无法找到出现关闭的RabbitMQ通道try块中的任何代码。有什么情况可以隐含地关闭频道?

编辑:我应该注意AlreadyClosedException抛出basicPublish在发布内调用。

+0

你如何解决这个问题? – 2016-02-23 12:53:41

AMQP通道在通道错误时关闭。两种常见的事情,可能会导致信道错误:

  • 尝试发布消息的交换不存在
  • 尝试发布与即时标志设置一条消息,没有与队列积极的消费设置

我会去了解一下你正在尝试使用使用addShutdownListener()赶上关闭事件,看看是什么原因导致它来发布信息的渠道上建立ShutdownListener。

+6

事实证明,JVM在内存不足时正在关闭AMQP连接。但是,由于某些原因,连接关闭时,通道上的关闭侦听器未触发。 – quanticle 2012-02-02 15:07:43

在我的情况下的另一个原因是,我错误地承认了一个消息两次。这会在第二次确认后在这种日志中导致RabbitMQ错误。

=ERROR REPORT==== 11-Dec-2012::09:48:29 === 
connection <0.6792.0>, channel 1 - error: 
{amqp_error,precondition_failed,"unknown delivery tag 1",'basic.ack'} 

我删除重复的确认后,错误消失,通道不再关闭,AlreadyClosedException也不见了。

+0

这种双重情况是一个很好的观点。很难看到问题。感谢评论我完全帮助了我。 – cramhead 2017-08-08 19:05:21

我想添加此信息为其他用户谁将会寻找这个话题

另一种可能原因接收信道封闭的例外是当发行商和消费者有不同的队列声明访问通道/队列/设置

出版商

channel.queueDeclare("task_queue", durable, false, false, null); 

工人

channel.queueDeclare("task_queue", false, false, false, null); 

从RabbitMQ的网站

RabbitMQ doesn't allow you to redefine an existing queue with different parameters and will return an error to any program that tries to do that 

我也有这个问题。之所以我的情况是这样的,首先我建立了队列耐用= false,并在日志文件中我有这个错误消息时我切换耐用为true:

"inequivalent arg 'durable' for queue 'logsQueue' in vhost '/': received 'true' but current is 'false'"

然后,我改变了队列的名称它为我工作。我认为RabbitMQ服务器将构建队列的记录保存在某处,并且不能将状态从持久状态更改为非持久状态,反之亦然。

我又耐久= false为新的队列,这一次我得到这个错误

"inequivalent arg 'durable' for queue 'logsQueue1' in vhost '/': received 'false' but current is 'true'"

我的假设是正确的。当我列出在rabbitMQ服务器队列:

rabbitmqctl list_queues 

我看到在服务器中的两个队列。

总之,2个解决方案是:1。 重命名这不是一个很好的解决方案 2.复位的RabbitMQ在队列名称:

rabbitmqctl stop_app 
rabbitmqctl reset 
rabbitmqctl start_app 
+0

一旦队列被声明,它的属性是不可变的。为什么不直接删除队列然后更改队列属性?重新启动整个经纪人只是为了改变一个队列的属性似乎有点激烈 – Daniel 2016-01-13 21:00:41