我们正在使用JMS和Spring Integration从Websphere MQ中读取消息。
<task:executor id="demoMessageReceiverChannelTE" pool-size="1-3" queue-capacity="5" keep-alive="1" rejection-policy="CALLER_RUNS"/>
<int:channel id="demoMessageReceiverChannel">
<int:dispatcher task-executor="demoMessageReceiverChannelTE"/>
<int:interceptors>
<int:ref bean="messageReceiverInterceptor" />
</int:interceptors>
</int:channel>
<jms:message-driven-channel-adapter
id="demoMesssageReceiverAdapter" channel="demoMessageReceiverChannel"
connection-factory="srcJmsConnectionFactory" destination="srcReceiverQueue"
error-channel="errorChannel" message-converter="demoIncomingMessageConverter"
transaction-manager="srcJmsTransactionManager" send-timeout="65000"
header-mapper="demoJmsHeaders" />
还有另一个系统,它将消息放在此队列中。 (超出我们的范围)
我们可以在队列中一次读取2000条消息。
有时,Message Listener会停止从Queue读取消息,当我尝试解决此问题时,它会说明队列中有一些未提交的消息,哪个侦听器尝试读取并且无法进一步处理挂在那儿。
当从队列中手动删除该消息时,它会完美地处理其他消息。
那么如何跳过这些未提交的消息,以便系统可以继续下一条消息?
答案 0 :(得分:4)
听起来像是一个经典的未处理的毒药消息问题。当应用程序读取无法处理的消息时,该消息将退回到队列中。然后再次读回,因为它位于队列的顶部。这导致消息看起来处于同步点,直到最终听者放弃并停止。
有时问题出现在应用中,而应用是明确调用ROLLBACK
的应用。有时虽然回滚发生,但应用程序甚至会看到消息。例如,如果消息无法转换为本地代码页,或其他低级错误。
如果发生这种情况,答案是定义一个回退队列,然后改变输入队列以指向它。例如,如果输入队列被调用SRC.RECEIVER.QUEUE
,您可以使用runmqsc
在QMgr上执行类似的操作:
DEFINE QL(SRC.RECEIVER.QUEUE.BKOUT)
ALTER QL(SRC.RECEIVER.QUEUE) BOQNAME(SRC.RECEIVER.QUEUE.BKOUT) BOTHRESH(15)
如果问题确实是有害消息,则问题消息将作为未提交的消息显示在回退队列中。只要应用程序针对源队列发出下一个COMMIT
,就会在回退队列中显示回退消息。如果源队列中没有其他消息到达,则在应用程序或QMgr调用ROLLBACK
时,有害消息将在退出队列中保持未提交状态,或者可能还原为源队列。
回退队列的设置很简单,应该是标准做法,所以无论是否解决问题,我都建议你这样做。请参阅信息中心的Handling poison messages in WebSphere MQ classes for JMS。