我的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级别的日志中也没有记录或错误报告。
没有任何其他的东西在监听这个队列,类似的事务也在同一个队列中得到成功处理。我不能以任何有保证的方式重现它,而且它完全是间歇性的。
有什么想法吗?
这里要吸取的教训是永远不要假设以下几点。
"没有其他东西在监听这个队列..."
有一些方法可以尝试并验证这一点。
检查当前有多少进程的INPUT队列是开放的
DIS QL(QUEUENAME) IPPROCS
显示当前队列打开的所有连接,使用 OPENOPTS
其中包括 MQOO_INPUT*
,这将同时显示IP地址(如果是客户端连接)和客户端提交的应用程序名称(APPLTAG)。
DIS CONN(*) TYPE(ALL) WHERE(OBJNAME EQ QUEUENAME)
以上两个都只显示了一个时间点的视图,如果你想找到一个正在连接从队列中读取消息然后断开连接的应用,那么你可能看不到它。 就像@MoragHughson在评论中提到的那样,启动一个活动跟踪,寻找到这个队列的连接,看看连接的IPsapplication名称是否符合预期,这样做的好处是,你可以在一段时间内看到所有连接到队列的东西。 下面是一个使用IBM MQ v9.1或更高版本的amqsevt并以IBM MQ v9.0或更高版本的队列管理器为目标的一个方法的例子(这依赖于一个叫做 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
'
问题已经解决,因为DEV队列管理器正在默默地消耗消息.这是无效的配置。