1

如果无法处理消息,例如由于某些外部端点故障,我需要重新传递消息。所以我正在使用以下 MDB 配置(值得一提的是,我正在使用 openMQ (Glassfish 4.1)):

@MessageDriven(mappedName = "MyQueue",  name = "MyQueue", activationConfig = {
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
@ActivationConfigProperty(propertyName = "endpointExceptionRedeliveryAttempts", propertyValue = "10"),
@ActivationConfigProperty(propertyName = "endpointExceptionRedeliveryInterval", propertyValue = "30000")})

这是 onMessage() 方法:

  @Override
  @TransactionAttribute(TransactionAttributeType.REQUIRED)
  public void onMessage (Message message)
  {
    try
    {
      //some processing here
    }
    catch (JMSException jmsException)
    {
      logger.log (Level.SEVERE, "Exception processing notification message", jmsException);
    }
    catch (BackingStoreException e)
    {
      // because of throwing RuntimeException, the message is going to be redelivered according to mdb configuration params(interval and attempts count)
      throw new RuntimeException ();
    }
  }

为了重新传递消息,也可以回滚事务,但是 openMQ 缺少重新传递间隔的属性,所以它不适合我:

https://github.com/javaee/openmq/issues/220

https://github.com/javaee/openmq/issues/23

https://github.com/javaee/openmq/issues/134

总而言之,重新传递工作正常,除了一个时刻:如果要重新传递消息,mdb 不会释放连接并为 endpointExceptionRedeliveryInterval * endpointExceptionRedeliveryAttempts 保留它,在我的例子中是 5 分钟。因此,maxPoolSize 的默认值为 32,32 条“坏”消息足以阻止 mdb。

有没有办法在消息重新传递的情况下释放连接?

4

1 回答 1

1

这是根据 JMS 规范的预期行为,我认为在某种消息处理正在进行时可能有某种方法可以释放连接对象。除了“4.3.5 关闭连接”之外,阅读此处和下面的JMS 规范是相关的:

如果连接的一个或多个会话的消息侦听器在调用连接关闭时正在处理消息,则连接的所有设施及其会话必须对这些侦听器保持可用,直到它们将控制权返回给 JMS 提供程序。

当调用连接关闭时,它不应该返回,直到消息处理被有序关闭。这意味着所有可能正在运行的消息侦听器都已返回,并且所有挂起的接收都已返回。

我不知道你为什么要用这么高的数字来重试机制,10次尝试太大了,我到目前为止看到的最多是3次,我认为你可以尝试调整你的重试机制数字,或者可能是有另一个专门用于重新交付的连接。

于 2017-06-08T21:08:06.730 回答