Closed spring-projects-issues closed 1 year ago
Stéphane Nicoll commented
does not call onException() on the JMS ExceptionListener of the underlying JMS Connection.
Sam, just to be sure, you meant ConnectionFactory
there, right? And we're talking about "our" ConnectionFactory
decorators there, right? It still unclear to me what the difference it would be with a caching connection factory provided by the JMS broker: that one would not be notified anyway...
Sam Brannen commented
Hi Stéphane,
It's been almost three years since I opened this issue. So my recollection of the exact details is a bit rusty. ;)
Sam, just to be sure, you meant ConnectionFactory there, right?
Good question. I think I actually meant Connection
. Though based on the Javadoc for javax.jms.Connection.setExceptionListener(ExceptionListener)
, perhaps we shouldn't be doing that.
However, my main goal was to solve the problem described in the forum (see link from this issue). I ran into the exact same issue and solved it as I described in the forum and this issue's description.
In the very least, I think that Spring's CachingConnectionFactory
should be automatically given a chance to recover from such exceptions, which is not currently the case.
Does that help clarify things?
Cheers,
Sam
Stéphane Nicoll commented
It does.
That being said, I am not sure that's how we should handle it. When such an issue happens, calling onException
will clear any session that was managed by the CachingConnectionFactory
whereas what we're looking after is a way to invalidate the Session
.
One way to deal with this issue would be to introduce a specific interface that ConnectionFactory
could implement. DMLC could detect if such interface is available and invoke a callback so that only that particular session (and the related connection) is handled.
Juergen Hoeller, what do you think?
Reading the description above, this sounds like misbehavior on the side of the JMS broker. The broker itself needs to notify the Connection-registered ExceptionListener, not the consumer. Once that works, a connection reset should work automatically, even with CachingConnectionFactory
. As for resetting a particular session only, since they typically all come from the same connection, it seems sensible to always clear all sessions and start with a fresh setup there.
Sam Brannen opened SPR-8616 and commented
Status Quo
When an exception is caught in
AbstractPollingMessageListenerContainer
'sdoReceiveAndExecute()
method,AbstractPollingMessageListenerContainer
delegates toAbstractMessageListenerContainer
'shandleListenerException()
method. If the suppliedThrowable
is aJMSException
, it gets passed toAbstractMessageListenerContainer
'sinvokeExceptionListener()
method for further processing. In turn,invokeExceptionListener()
callsonException()
on the JMSExceptionListener
that was registered with theAbstractMessageListenerContainer
.AbstractMessageListenerContainer
'sinvokeExceptionListener()
method does not callonException()
on the JMSExceptionListener
of the underlying JMSConnection
.Consequently, connection errors that occur while processing inbound messages in a Spring MessageListenerContainer do not get propagated to the underlying connection. If the underlying connection is a shared connection that was created by Spring's
SingleConnectionFactory
orCachingConnectionFactory
, that now broken connection will be reused by subsequent clients even though it should have been reset due to the connection failure. This leads to an endless loop of retries with invalid connections that will never work, and in the end the application will likely have to be restarted in order to obtain new connections.Goal
AbstractMessageListenerContainer
'sinvokeExceptionListener()
method should callonException()
:ExceptionListener
that was registered with theAbstractMessageListenerContainer
(i.e., the status quo)ExceptionListener
of the underlying JMSConnection
Note that
DefaultMessageListenerContainer
'srefreshDestination()
method already provides similar support for refreshing a possibly invalid destination name for aCachingDestinationResolver
.Work-around
The current work-around is to set the
exceptionListener
property of theDefaultMessageListenerContainer
to theCachingConnectionFactory
. This works sinceCachingConnectionFactory
implements the JMSExceptionListener
interface, andCachingConnectionFactory
'sonException()
method will internally reset the connection (i.e., clear the cache). Note, however, that theexceptionListener
property is unfortunately not exposed as an attribute via the<jms:listener-container>
XML namespace. The following XML-based configuration has been tested as a suitable work-around configuration:Affects: 3.0.5
Reference URL: http://forum.springsource.org/showthread.php?96821-DefaultMessageListenerContainer-CachingConnectionFactory-tomcat-and-WebSphere-MQ