spring-jms 5.3.19
Hello community, We are using org.springframework.jms.listener.SimpleMessageListenerContainer (SMLC) as a message listener for azure service bus (ASB). We are facing some strange issues when azure is not available for a short period of time and our SMLC is not able to reconnect. We end up with application running but not consuming any messages. As you can imagine, this took some time to realize and lot of messages were not processed.
Yes – monitoring your message service for incoming and outgoing messages to spot this kind of problem is a good thing (we were not so lucky to had it)
Yes – there is a simple mechanism in SMLC for reconnecting, but in our case, it is not sufficient. It may happen that it can try only once and there is no hook in case of unsuccessful reconnecting.
Yes – in this case the use of DefaultMessageListenerContainer (DMLC) would seem as reasonable – I has configurable reconnecting strategy. But we cannot use it. DMLC is using pull mechanism, so he constantly makes requests to ASB which leads to throttling problem in ASB and to solve it we would have to upgrade our pricing plan – which is not an option – we like the SMLC push approach which is not producing as many requests to ASB
After some time spent with SMLC we came with a solution, but it is not a nice solution because we reused(misused) onException method and we execute it over and over again to successfully reconnect with our broker – because only this method is capable to reconnect with message provider. The reason is - only here you are able to set sessions and consumers to null:
public void onException(JMSException ex) {
// First invoke the user-specific ExceptionListener, if any.
invokeExceptionListener(ex);
// Now try to recover the shared Connection and all consumers...
if (this.recoverOnException) {
if (logger.isDebugEnabled()) {
logger.debug("Trying to recover from JMS Connection exception: " + ex);
}
try {
synchronized (this.consumersMonitor) {
this.sessions = null;
this.consumers = null;
}
refreshSharedConnection();
initializeConsumers();
logger.debug("Successfully refreshed JMS Connection");
}
catch (JMSException recoverEx) {
logger.debug("Failed to recover JMS Connection", recoverEx);
logger.error("Encountered non-recoverable JMSException", ex);
}
}
}
Is it possible to take this code
synchronized (this.consumersMonitor) {
this.sessions = null;
this.consumers = null;
}
refreshSharedConnection();
initializeConsumers();
logger.debug("Successfully refreshed JMS Connection");
out to some method and call it directly - like void/boolean refreshContainer()? In this case it can still remain simple, but you gain the ability to refresh connections/consumers and the developer can implement for example backoff as he wants. Also it would be nice to somehow know if you reconnected successfully or not.
Thank you for consideration of this proposal.
Comment From: snicoll
Thanks for the report.
We are facing some strange issues when azure is not available for a short period of time and our SMLC is not able to reconnect.
Can you provide more feedback? Is the reception dying with no exception? This could be fixed by configuring the JMS provider accordingly. Unfortunately I don't know enough about Azure to know for sure. From your report, it looks like you didn't get any feedback it died, but you can figure it out yourself, hence you calling onException
manually.
Please explain how you'd figured it out. Providing as many detail as possible will help us make hopefully the right call.
Comment From: spring-projects-issues
If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.
Comment From: spring-projects-issues
Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.