Javadoc for org.springframework.jms.listener.AbstractMessageListenerContainer
states, that if
"sessionAcknowledgeMode" set to "CLIENT_ACKNOWLEDGE": Automatic message acknowledgment after successful listener execution; no redelivery in case of exception thrown.
I guess, "no redelivery in case of exception thrown" means, that message would not be redelivered (so, my guess, it would be acknowledged), even if there's an exception thrown in the jms listener. But, well, exception thrown from listener means that call to it wasn't successful, and there should be redelivery due to no acknowledgement.
The question is:
What actually should happen with message acknowledgement in case of exception thrown in the jms listener?
What really happens, might be seen from this stacktrace:
at org.springframework.jms.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:98)
at org.springframework.jms.listener.adapter.MessagingMessageListenerAdapter.onMessage(MessagingMessageListenerAdapter.java:66)
at org.springframework.jms.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:660)
at org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:620)
at org.springframework.jms.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:591)
at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.doReceiveAndExecute(AbstractPollingMessageListenerContainer.java:308)
at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:246)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1142)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1134)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:1031)
Line 5 of the stacktrace is of particular interest. Code there basically means, that (mostly) whatever exception thrown from the listener will bypass the ackowledgement which is done in org.springframework.jms.listener.AbstractMessageListenerContainer#commitIfNecessary
.
That's ok, but what does "no redelivery in case of exception thrown" mean then?
Additional info:
spring-jms:4.1.2
<bean id="someListenerContainerFactory" class="org.springframework.jms.config.DefaultJmsListenerContainerFactory">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="concurrency" value="1-10"/>
<property name="sessionAcknowledgeMode">
<util:constant static-field="javax.jms.Session.CLIENT_ACKNOWLEDGE"/>
</property>
</bean>
It depends on which listener container you use; when using AUTO ack mode, the
SimpleMessageListenerContainer
acks after the listener returns (i.e. a traditional JMSMessageListener
). TheDefaultMessageListenerContainer
acks before the listener is invoked, so you needacknowledgeMode="transacted"
to prevent message loss.The javadocs in this area were a bit misleading and have been improved recently.
With CLIENT_ACKNOWLEDGE, you're on your own to do the acks. That doc just means you are at the whim of the broker. According to the JMS message javadoc:
In my experience it is best to use auto ack with an
SMLC
and transactions withDMLC
.