问题描述
我有一个JMS 2.0 MessageListener,即使已成功处理了消息(通过日志确认),它似乎也会偶尔重新处理消息。我怀疑需要完成session.commit(),但是我不确定,因为在大多数情况下,不会重试消息。据我了解,AUTO_ACKNowLEDGE是默认设置,但同样,我不确定它如何用于SessionAwareMessageListener。
相关的spring.xml部分看起来像这样
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
:
:
<property name="messageListener" ref="myMessageListener" />
<property name="maxConcurrentConsumers" value="1" />
<property name="receiveTimeout" value="5000" />
<property name="sessionTransacted" value="true" />
</bean>
MessageListener的实现如下
public class MyMessageListener implements SessionAwareMessageListener {
// All spring autowired objects
:
:
@Override
public void onMessage(Message message,Session session)
{
logger.debug("JMSMessage ID : " + message.JMSMessageId,"Entering onMessage() ...");
logger.debug("JMSMessage ID : " + message.JMSMessageId,"Retry Count : " + message.getIntProperty("JMSXDeliveryCount"));
try
{
}
catch(JMSException e)
{
// Log something
throw new RuntimeException(e);
}
catch(Exception ex)
{
if(certain types of exceptions)
{
session.rollback();
System.Exit(1);
}
throw new RuntimeException(ex);
}
// THE FOLLOWING IS THE LAST LINE IN onMessage()
logger.debug("JMSMessage ID : " + message.JMSMessageId,"Completed successfully !");
}
}
所以,我现在看到的几乎所有消息都在日志中有
:
JMSMessage Id : 1234,Entering onMessage()
JMSMessage Id : 1234,Retry count : 1
:
JmsMessage Id : 1234,Completed successfully!
JmsMessage Id : 3344,Entering onMessage() // New message taken up for processing.
JMSMessage Id : 3344,Retry count : 1
问题在于,有时(在成千上万条消息之后),我会在日志中看到这一点
:
JMSMessage Id : 5566,Entering onMessage()
JMSMessage Id : 5566,Retry count : 1
:
JmsMessage Id : 5566,Completed successfully!
JMSMessage Id : 5566,Entering onMessage() // WHY IS JMS PROCESSING THE SAME MESSAGE (MESSAGEID : 5566) AGAIN ?
JMSMessage Id : 5566,Retry count : 2
:
:
解决方法
当您将sessionTransacted
设置为true时,忽略确认模式,甚至可以设置一个特殊值来表示它未被使用,从其他示例中可以看到:
<property name="sessionAcknowledgeModeName" value="SESSION_TRANSACTED"/>
根据Gary Russell对stackoverflow问题Spring DMLC message consumption: auto_ack vs Transacted Session的回答,如果您将DMLC的sessionTransacted
设置为true,则在调用侦听器后,如果侦听器抛出异常,则由DMLC提交会话交易回滚的异常。