简体   繁体   English

RabbitMQ Java客户端 - 如何合理地处理异常和关闭?

[英]RabbitMQ Java client - How to sensibly handle exceptions and shutdowns?

Here's what I know so far (please correct me): 这是我目前所知的(请纠正我):

In the RabbitMQ Java client, operations on a channel throw IOException when there is a general network failure (malformed data from broker, authentication failures, missed heartbeats). 在RabbitMQ Java客户端中,当存在一般网络故障(来自代理的格式错误的数据,身份验证失败,错过的心跳)时,通道上的操作会抛出IOException

Operations on a channel can also throw the ShutdownSignalException unchecked exception, typically an AlreadyClosedException when we tried to perform an action on the channel/connection after it has been shut down. 通道上的操作也可以抛出ShutdownSignalException未经检查的异常,当我们在关闭后尝试对通道/连接执行操作时,通常是AlreadyClosedException

The shutting down process happens in the event of "network failure, internal failure or explicit local shutdown" (eg via channel.close() or connection.close()). 关闭过程在“网络故障,内部故障或显式本地关闭” (例如通过channel.close()或connection.close())的情况下发生。 The shutdown event propagates down the "topology", from Connection -> Channel -> Consumer, and when the Channel it calls the Consumer's handleShutdown() method gets called. 关闭事件沿着“拓扑”向下传播,来自Connection - > Channel - > Consumer,当它调用的Channel调用Consumer的handleShutdown()方法时。

A user can also add a shutdown listener which is called after the shutdown process completes. 用户还可以添加在关闭过程完成后调用的关闭侦听器。

Here is what I'm missing: 这是我缺少的:

  1. Since an IOException indicates a network failure, does it also initiate a shutdown request? 由于IOException指示网络故障,它是否也会启动关闭请求?
  2. How does using auto-recovery mode affect shutdown requests? 使用自动恢复模式如何影响关闭请求? Does it cause channel operations to block while it tries to reconnect to the channel, or will the ShutdownSignalException still be thrown? 是否会导致通道操作在尝试重新连接到通道时阻塞,或者是否仍会抛出ShutdownSignalException?

Here is how I'm handling exceptions at the moment, is this a sensible approach? 这是我现在处理异常的方式,这是一种明智的方法吗?

My setup is that I'm polling a QueueingConsumer and dispatching tasks to a worker pool. 我的设置是我正在轮询QueueingConsumer并将任务分派给工作池。 The rabbitmq client is encapsulated in MyRabbitMQWrapper here. rabbitmq客户端封装在MyRabbitMQWrapper When an exception occurs polling the queue I just gracefully shutdown everything and restart the client. 当轮询队列时发生异常时,我只是优雅地关闭所有内容并重新启动客户端。 When an exception occurs in the worker I also just log it and finish the worker. 当工作者发生异常时,我也只是记录它并完成工作。

My biggest worry (related to Question 1): Suppose an IOException occurs in the worker, then the task doesn't get acked. 我最大的担忧(与问题1相关):假设在工作者中发生IOException,则任务不会被激活。 If the shutdown does not then occur, I now have an un-acked task that will be in limbo forever. 如果关闭没有发生,我现在有一个未完成的任务将永远处于不确定状态。

Pseudo-code: 伪代码:

class Main {
    public static void main(String[] args) {
        while(true) {
            run();
            //Easy way to restart the client, the connection has been
            //closed so RabbitMQ will re-queue any un-acked tasks.
            log.info("Shutdown occurred, restarting in 5 seconds");
            Thread.sleep(5000);
        }
    }

    public void run() {
      MyRabbitMQWrapper rw = new MyRabbitMQWrapper("localhost");

      try {
        rw.connect();

        while(!Thread.currentThread().isInterrupted()) {
           try {
               //Wait for a message on the QueueingConsumer
               MyMessage t = rw.getNextMessage();
               workerPool.submit(new MyTaskRunnable(rw, t));
           } catch (InterruptedException | IOException | ShutdownSignalException e) {
               //Handle all AMQP library exceptions by cleaning up and returning
               log.warn("Shutting down", e);
               workerPool.shutdown();
               break;
           }
        }
      } catch (IOException e) {
        log.error("Could not connect to broker", e);
      } finally {
        try { 
            rw.close(); 
        } catch(IOException e) { 
            log.info("Could not close connection");
        }
      }
    }
}

class MyTaskRunnable implements Runnable {
    ....

    public void run() {
        doStuff();
        try {
            rw.ack(...);
        } catch (IOException | ShutdownSignalException e) {
            log.warn("Could not ack task");
        }
    }
}

您可以查看Lyra是否从意外的连接/通道/消费者关闭中自动恢复。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM