为什么我的 RabbitMQ 通道不断关闭?

发布于 2024-12-26 15:41:46 字数 1244 浏览 3 评论 0原文

我正在调试一些使用 Apache POI 从 Microsoft Office 文档中提取数据的 Java 代码。有时,它会遇到大文档,POI 会在内存不足时崩溃。此时,它会尝试将错误发布到 RabbitMQ,以便其他组件知道此步骤失败并采取适当的操作。但是,当它尝试发布到队列时,它会收到 com.rabbitmq.client.AlreadyClosedException(干净连接关闭;原因:尝试使用关闭通道)

这是错误处理程序代码:

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());  
}

我在 try 块中找不到任何关闭 RabbitMQ 通道的代码。是否存在可以隐式关闭通道的情况?

编辑:我应该注意到 AlreadyClosedException 是由发布内的 basicPublish 调用引发的。

I'm debugging some Java code that uses Apache POI to pull data out of Microsoft Office documents. Occasionally, it encounter a large document and POI crashes when it runs out of memory. At that point, it tries to publish the error to RabbitMQ, so that other components can know that this step failed and take the appropriate actions. However, when it tries to publish to the queue, it gets a com.rabbitmq.client.AlreadyClosedException (clean connection shutdown; reason: Attempt to use closed channel).

Here's the error handler code:

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);
}

For completeness, here's the publish method:

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());  
}

I can't find any code within the try block that appears to close the RabbitMQ channel. Are there any circumstances in which the channel could be closed implicitly?

EDIT: I should note that the AlreadyClosedException is thrown by the basicPublish call inside publish.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

紫竹語嫣☆ 2025-01-02 15:41:47

对于那些想知道为什么他们的消费通道关闭的人,请检查您是否多次尝试确认或拒绝交付。

在rabbitmq日志中你会看到如下消息:

操作basic.ack导致通道异常precondition_failed:
未知的交货标签...

For those who wonder why their consuming channels are closing, check if you try to Ack or Nack a delivery more than once.

In the rabbitmq log you would see messages like:

operation basic.ack caused a channel exception precondition_failed:
unknown delivery tag ...

初吻给了烟 2025-01-02 15:41:47

我也遇到了这个问题。我的情况的原因是,首先我使用 Durable = false 构建了队列,并且在日志文件中,当我将 Durable 切换为 true 时,我收到了此错误消息:

“虚拟主机“/”中队列“logsQueue”的不等价参数“durable”:
收到“真”,但当前为“假””

然后,我更改了队列的名称,它对我有用。我假设 RabbitMQ 服务器将构建队列的记录保存在某处,并且它无法将状态从持久更改为非-durable,反之亦然。

我再次为新队列设置了durable=false,这次我得到了这个错误。

“虚拟主机“/”中队列“logsQueue1”的不等价参数“持久”:
收到“假”,但当前为“真””

我的假设是正确的。当我通过以下方式列出rabbitMQ服务器中的队列时:

rabbitmqctl list_queues 

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

总而言之,有两种解决方案:
1.重命名队列的名称这不是一个好的解决方案
2.通过以下方式重置rabbitMQ:

rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl start_app

I also had this problem. The reason for my case was that, first I built the queue with durable = false and in the log file I had this error message when I switched durable to true:

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

Then, I changed the name of the queue and it worked for me. I assumed that the RabbitMQ server keeps the record of the built queues somewhere and it cannot change the status from durable to non-durable and vice versa.

Again I made durable=false for the new queue and this time I got this error

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

My assumption was true. When I listed the queues in rabbitMQ server by:

rabbitmqctl list_queues 

I saw both queues in the server.

To summarize, 2 solutions are:
1. renaming the name of the queue which is not a good solution
2. resetting rabbitMQ by:

rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl start_app
对不⑦ 2025-01-02 15:41:46

AMQP 通道因通道错误而关闭。可能导致通道错误的两种常见情况:

  • 尝试将消息发布到不存在的交换器
  • 尝试发布带有立即标志集的消息,但该消息没有带有活动消费者集的队列

我会研究设置在您尝试使用的通道上启动 ShutdownListener 使用 addShutdownListener() 捕获关闭事件并查看导致的原因 它。

An AMQP channel is closed on a channel error. Two common things that can cause a channel error:

  • Trying to publish a message to an exchange that doesn't exist
  • Trying to publish a message with the immediate flag set that doesn't have a queue with an active consumer set

I would look into setting up a ShutdownListener on the channel you're trying to use to publish a message using the addShutdownListener() to catch the shutdown event and look at what caused it.

悲歌长辞 2025-01-02 15:41:46

就我而言,另一个原因是我错误地确认了一条消息两次。这会导致第二次确认后日志中出现这样的 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 也消失了。

Another reason in my case was that by mistake I acknowledged a message twice. This lead to RabbitMQ errors in the log like this after the second acknowledgment.

=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'}

After I removed the duplicate acknowledgement then the errors went away and the channel did not close anymore and also the AlreadyClosedException were gone.

电影里的梦 2025-01-02 15:41:46

我想为将搜索此主题的其他用户添加此信息

接收通道关闭异常的另一个可能原因是当发布者和消费者使用不同的队列声明/设置从 RabbitMQ 站点访问通道

队列

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

/

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

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

I'd like to add this information for other users who will be searching for this topic

Another possible reason for Receiving a Channel Closed Exception is when Publishers and Consumers are accessing Channel/Queue with different queue declaration/settings

Publisher

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

Worker

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

From RabbitMQ Site

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
旧瑾黎汐 2025-01-02 15:41:46

显然,AMQP 连接和/或通道突然关闭的原因有很多。就我而言,队列中有太多未确认的消息,因为消费者没有指定 prefetch_count< /a> 因此连接每约 1 分钟就会终止一次。通过将消费者的预取计数设置为非零值来限制未确认消息的数量解决了该问题。

channel.basicQos(100); 

Apparently, there are many reasons for the AMQP connection and/or channels to close abruptly. In my case, there was too many unacknowledged messages on the queue because the consumer didn't specify the prefetch_count so the connection was getting terminated every ~1min. Limiting the number of unacknowledged messages by setting the consumer's prefetch count to a non-zero value fixed the problem.

channel.basicQos(100); 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文