【问题标题】:Spring DefaultJmsListenerContainerFactory dropping messages on JBoss EAP 7Spring DefaultJmsListenerContainerFactory 在 JBoss EAP 7 上丢弃消息
【发布时间】:2020-06-15 15:13:06
【问题描述】:

我有以下 Spring JMS 工厂配置:

@Bean(name = "jmsListenerFactory")
public DefaultJmsListenerContainerFactory jmsListenerFactory() throws Exception {
    DefaultJmsListenerContainerFactory container = new DefaultJmsListenerContainerFactory();
    container.setErrorHandler(new MqErrorHandler());
    container.setConnectionFactory(connectionFactory);
    container.setTransactionManager(transactionManager);
    container.setConcurrency("5-10");
    return container;
}   

监听器设置:

@JmsListener(destination = ACK_QUEUE, containerFactory = "jmsListenerFactory")
@Transactional
public void receive(String response) throws Exception {
    try {
        logger.debug(response);
        Msg ackNack = (Msg) unmarshaller.unmarshal(new StringReader(response));
        ... and so on
        ... should acknowledge JMS and commit DB update
}

JTA 事务管理器:

public JtaTransactionManager jbossTransactionManager() throws Exception {
    JtaTransactionManager transactionManager = new JtaTransactionManager();
    transactionManager.setTransactionManagerName("java:/TransactionManager");
    return transactionManager;
}

我有一个 Oracle 数据库和一个通过 JNDI 包含的 JMS 连接工厂资源,两者都与 XA 兼容。

问题是某些 JMS 消息没有发送到侦听器。它们 100% 提供给队列,但就像它们只是“消失”一样。即使达到 TRACE 级别,也不会在日志中报告任何日志记录或错误。

没有其他人正在监听此队列,并且正在从同一队列成功处理类似的事务。我无法以任何有保证的方式重现它,而且它是完全断断续续的。

有什么想法吗?

【问题讨论】:

  • 运行某种跟踪,例如Activity Trace,看看是什么让你的队列中的消息。
  • @MoragHughson Activity Trace 是一个很好的建议。

标签: spring ibm-mq jboss7.x spring-jms jta


【解决方案1】:

这里要吸取的教训是永远不要假设以下内容:

“没有其他人在听这个队列..”

有多种方法可以尝试验证这一点:

  1. 检查当前有多少进程为 INPUT 打开队列:

    DIS QL(QUEUENAME) IPPROCS

  2. 显示当前使用OPENOPTS 打开队列的所有连接,包括MQOO_INPUT*,这将显示 IP 地址(如果是客户端连接)和客户端提供的应用程序名称 (APPLTAG)。

    DIS CONN(*) TYPE(ALL) WHERE(OBJNAME EQ QUEUENAME)

  3. 以上两个都只显示时间点视图,如果你试图找到一个正在连接的应用程序从队列中读取消息然后断开连接,那么你可能看不到它。

    作为@ MoragHughson 在评论中提到,启动活动跟踪并查找与此队列的连接,并查看连接的 IP/应用程序名称是否符合预期,这样做的好处是您可以在一段时间内看到所有具有连接到队列。

    下面是使用 IBM MQ v9.1 或更高版本中的 amqsevt 并针对 IBM MQ v9.0 或更高版本队列管理器(这依赖于开源JSON 处理器称为 jq)。下面的示例将一直运行到 5 分钟(300 秒)内没有任何活动或直到按下某个键(您可以通过增加 -w 值来增加时间):

#Replace the string _REPLACE_WITH_QMGR_NAME_ with your queue manager name in both places.
#Replace the string _REPLACE_WITH_QUEUE_NAME_ with your queue name.

amqsevt -m _REPLACE_WITH_QMGR_NAME_ -t '$SYS/MQ/INFO/QMGR/_REPLACE_WITH_QMGR_NAME_/ActivityTrace/ConnectionId/#' -w 300 -o json | jq -r '
.eventData
| [.channelName, .channelType, .connectionName, .applName, .remoteProduct, .remoteVersion] as $x
| ( .activityTrace[]
    | select(.objectName == "_REPLACE_WITH_QUEUE_NAME_") | [.operationTime]
      + $x
      + [.operationId, .objectName, .resolvedQueueName, .reasonCode.value, .putDate, .putTime] )
| @csv
'

【讨论】:

    【解决方案2】:

    问题已解决,因为 DEV 队列管理器正在静默使用消息...这是无效的配置。

    【讨论】:

    • 很高兴你们都排好了 - 建议您接受(按勾选)@JoshMc 的答案,因为它对未来的读者来说是一个极好的且非常有用的答案。
    猜你喜欢
    • 2017-05-11
    • 1970-01-01
    • 2019-12-14
    • 1970-01-01
    • 1970-01-01
    • 2019-12-21
    • 1970-01-01
    • 2017-05-27
    • 1970-01-01
    相关资源
    最近更新 更多