通过运行RabbitMQ使用者安全结束java应用程序的最佳方法是什么

通过运行RabbitMQ使用者安全结束java应用程序的最佳方法是什么,java,rabbitmq,Java,Rabbitmq,我们有一个独立的java应用程序在Debian机器上进行一些后台处理。它必须处理的作业通过RabbitMQ消息发送 当java应用程序需要升级时,我们需要停止它(杀死它)。但我们必须确保目前没有消费者在处理消息。根据您的经验,实现这一目标的最佳方式是什么 我们试图向消费者发送“关机”消息,但似乎无法关闭队列或通道?!它冻结了应用程序! 或者有没有另一种解决方案,例如我们可以自动关闭应用程序,而不必在linux中执行kill命令 谢谢分享你的经验 问候语RabbitMQ Java库不提供(AFAI

我们有一个独立的java应用程序在Debian机器上进行一些后台处理。它必须处理的作业通过RabbitMQ消息发送

当java应用程序需要升级时,我们需要停止它(杀死它)。但我们必须确保目前没有消费者在处理消息。根据您的经验,实现这一目标的最佳方式是什么

我们试图向消费者发送“关机”消息,但似乎无法关闭队列或通道?!它冻结了应用程序! 或者有没有另一种解决方案,例如我们可以自动关闭应用程序,而不必在linux中执行kill命令

谢谢分享你的经验


问候语

RabbitMQ Java库不提供(AFAIK)任何会在某些消息仍在处理时自动推迟使用者进程关闭的功能。因此,你必须自己做这件事

如果您的应用程序可以容忍,请关闭它。此时未确认的任何消息都将保留在代理内的队列中,并在使用者返回时重新传递

如果您不能容忍这种情况,并且必须确保所有正在进行的消息处理完成,那么您需要遵循类似于中的建议,并在关机处理程序中执行以下操作:

  • 将“所有线程都应退出”标志设置为true
  • 加入线程池中的每个线程
  • 优雅地退出
  • 这意味着每个消息处理线程(假设有多个线程同时处理消息)都需要遵循以下常规模式:

  • 从队列中提取消息并对其进行处理
  • 确认刚刚处理的消息
  • 如果“所有线程都应该退出”标志为真,则退出线程函数
  • 冲洗,重复
  • 希望能有所帮助。

    以下是我的看法

    我创建了DefaultConsumer(BasicConsumer)的子类,它提供isCancelled()并实现handleCancelLok(),它将“取消的标志”设置为true

    启动顺序:

    consumers = new ArrayList<BasicConsumer>();
    consumers.add(...)
    
    // Cancel all consumers
    for (BasicConsumer consumer : consumers) {
      try {
        consumer.getChannel().basicCancel(consumer.getConsumerTag());
      } catch (Exception e) {
        // report
      }
    }
    
    // Wait for all consumers to be cancelled
    Timeout timeout = ...;
    while (!consumers.isEmpty() && !timeout.isElapsed()) {
      // Remove cancelled consumers
      for (Iterator<BasicConsumer> iterator = consumers.iterator(); iterator.hasNext();) {
        if (iterator.next().isCancelled())
          iterator.remove();
      }
    }
    
    // Here we could force-close the remaining timed-out consumers if we
    // used our own ExecutorService by shutting down all of its threads.
    connection.close();
    
    consumers=newarraylist();
    消费者。添加(…)
    
    停止顺序:

    consumers = new ArrayList<BasicConsumer>();
    consumers.add(...)
    
    // Cancel all consumers
    for (BasicConsumer consumer : consumers) {
      try {
        consumer.getChannel().basicCancel(consumer.getConsumerTag());
      } catch (Exception e) {
        // report
      }
    }
    
    // Wait for all consumers to be cancelled
    Timeout timeout = ...;
    while (!consumers.isEmpty() && !timeout.isElapsed()) {
      // Remove cancelled consumers
      for (Iterator<BasicConsumer> iterator = consumers.iterator(); iterator.hasNext();) {
        if (iterator.next().isCancelled())
          iterator.remove();
      }
    }
    
    // Here we could force-close the remaining timed-out consumers if we
    // used our own ExecutorService by shutting down all of its threads.
    connection.close();
    
    //取消所有使用者
    for(基本消费者:消费者){
    试一试{
    consumer.getChannel().basicCancel(consumer.getConsumerTag());
    }捕获(例外e){
    //报告
    }
    }
    //等待所有消费者被取消
    超时=。。。;
    而(!consumers.isEmpty()&&!timeout.iseproved()){
    //删除已取消的消费者
    for(Iterator Iterator=consumers.Iterator();Iterator.hasNext();){
    if(iterator.next().isCancelled())
    iterator.remove();
    }
    }
    //在这里,如果我们
    //通过关闭所有线程来使用我们自己的ExecutorService。
    connection.close();
    

    相关RabbitMQ ML线程:

    您可以使用持久消息,在这种情况下,您可以随时杀死它,因为返回或发出的消息不会丢失。松散耦合/异步com是人们使用MQs的众多原因之一。@Shahzeb是的,我们使用持久消息,对于某些作业,我们可以简单地终止它,并在重新启动时重新处理消息。但是有一项特殊的工作是使用外部api做一些业务,它不能被中断,因为一旦在这个过程中,就不可能在同一个请求上重新运行它。我确实理解这个理论,但我们使用RabbitMQ的方式并不是专门创建多个线程。这一切都是通过创建多个频道来完成的。因此,我真的不明白如何实现这一点。但我会根据你的建议继续寻找。再次使用Thx。如果关闭关机处理程序中的所有通道(除了如上所述等待处理所有正在进行的消息),该怎么办?这难道不能让你优雅地关机吗?嗨,布莱恩。我确实找到了一个有效的解决办法。你的帖子对此很有帮助,但我还没有找到时间发布解决方案。我希望这周我能做到!