繁体   English   中英

使用spring-websocket和RabbitMQ代理订阅已删除的队列(队列NOT_FOUND)

[英]Subscribing to a removed queue with spring-websocket and RabbitMQ broker (Queue NOT_FOUND)

我在Tomcat8上有一个spring-websocket(4.1.6)应用程序,该应用程序使用STOMP RabbitMQ(3.4.4)消息代理进行消息传递。 当客户端(Chrome 47)启动应用程序时,它会订阅一个端点,从而创建持久队列。 当此客户端从端点退订时,RabbitMQ将在定制的RabbitMQ策略中定义的30秒后清理队列。 当我尝试重新连接到具有已清理队列的端点时,在RabbitMQ日志中收到以下异常:“ NOT_FOUND-虚拟主机'/'\\ n中没有队列'position-updates-user9zm_szz9'。 我不想使用自动删除队列,因为我有一些重新连接逻辑,以防websocket连接中断。

通过将以下代码添加到spring-websocket-portfolio github示例中,可以重现此问题。

在容器div中的index.html中添加:

<button class="btn" onclick="appModel.subscribe()">SUBSCRIBE</button>
<button class="btn" onclick="appModel.unsubscribe()">UNSUBSCRIBE</button>

在Portfolio.js中替换:

stompClient.subscribe("/user/queue/position-updates", function(message) {

有:

positionUpdates = stompClient.subscribe("/user/queue/position-updates", function(message) {

并添加以下内容:

  self.unsubscribe = function() {
    positionUpdates.unsubscribe();
  }

  self.subscribe = function() {
    positionUpdates = stompClient.subscribe("/user/queue/position-updates", function(message) {
      self.pushNotification("Position update " + message.body);
      self.portfolio().updatePosition(JSON.parse(message.body));
    });
  }

现在,您可以通过以下方式重现该问题:

  1. 启动应用程序
  2. 点击退订
  3. 在RabbitMQ控制台中删除position-updates队列
  4. 点击订阅

通过chrome devtools和RabbitMQ日志在websocket框架中找到错误消息。

如果websocket连接中断,请重新连接逻辑。

vhost中没有队列“ position-updates-user9zm_szz9”

是完全不同的故事。

我建议您在删除队列的情况下实现“重新订阅”逻辑。

实际上,这就是STOMP的工作方式:它为订阅创建auto-deleted (生成的)队列,是的,在取消订阅时将其删除。

请参阅RabbitMQ STOMP适配器手册中的更多信息。

从另一侧考虑订阅现有的AMQP队列:

要解决在STOMP适配器外部创建的现有队列,可以使用/amq/queue/<name>形式的目标。

问题是,如果RabbitMQ策略删除了队列,Stomp将不会重新创建队列。 我通过在激发SessionSubscribeEvent时自己创建队列来解决此问题。

public void onApplicationEvent(AbstractSubProtocolEvent event) {
   if (event instanceof SessionSubscribeEvent) {
      MultiValueMap nativeHeaders = (MultiValueMap)event.getMessage().getHeaders().get("nativeHeaders");
      List destination = (List)nativeHeaders.get("destination");
      String queueName = ((String)destination.get(0)).substring("/queue/".length());

      try {
         Connection connection = connectionFactory.newConnection();
         Channel channel = connection.createChannel();
         channel.queueDeclare(queueName, true, false, false, null);
      } catch (IOException e) {
         e.printStackTrace();
      }
   }
}

暂无
暂无

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

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