2

1. Background

We are evaluating Spring JMS and testing out the JMSTemplate for various scenarios - queues, topics (durable, non-durable).

We experienced message loss for non-durable topic subscribers and would like to seek clarifications here.

2. Problem Statement

a) We wrote a standalone java program that would call the JMSTemplate.receive method every n secs to receive messages synchronously from a non-durable topic**.

b) We noticed that there is always message loss after the 1st invocation of the JMSTemplate.receive method. This was due to the JMSTemplate.receive method stopping the connection when it reaches ConnectionFactoryUtils.releaseConnection(...).

JMSTemplate:

public <T> T execute(SessionCallback<T> action, boolean startConnection) throws JmsException 
{
        Assert.notNull(action, "Callback object must not be null");
        Connection conToClose = null;
        Session sessionToClose = null;
        try {
              Session sessionToUse = ConnectionFactoryUtils.doGetTransactionalSession(
                          getConnectionFactory(), this.transactionalResourceFactory, startConnection);
              if (sessionToUse == null) {
                    conToClose = createConnection();
                    sessionToClose = createSession(conToClose);
                    if (startConnection) {
                          conToClose.start();
                    }
                    sessionToUse = sessionToClose;
              }
              if (logger.isDebugEnabled()) {
                    logger.debug("Executing callback on JMS Session: " + sessionToUse);
              }
              return action.doInJms(sessionToUse);
        }
        catch (JMSException ex) {
              throw convertJmsAccessException(ex);
        }
        finally {
              JmsUtils.closeSession(sessionToClose);
              ConnectionFactoryUtils.releaseConnection(conToClose, getConnectionFactory(), startConnection); // the connection is stopped here
        }
  }

ConnectionFactoryUtils.releaseConnection(...):

public static void releaseConnection(Connection con, ConnectionFactory cf, boolean started) {
            if (con == null) {
                  return;
            }
            if (started && cf instanceof SmartConnectionFactory && ((SmartConnectionFactory) cf).shouldStop(con)) {
                  try {
                        con.stop(); // connection was stopped here
                  }
                  catch (Throwable ex) {
                        logger.debug("Could not stop JMS Connection before closing it", ex);
                  }
            }
            try {
                  con.close();
            }
            catch (Throwable ex) {
                  logger.debug("Could not close JMS Connection", ex);
            }

3. Validation with Spring Documentation

The Spring JMS documentation advised to use pooled connections, so we made sure we did.

Our java program is obtaining the JMS Connection Factories from WLS JMS and MQ JMS (LDAP) Providers and decorated with SingleConnectionFactory and CachingConnectionFactory in respective test cases.

This is what we observed during testing:

a) SingleConnectionFactory - Connection was stopped (Consumer/Session were closed as well).

b) CachingConnectionFactory - Connection was also stopped (although Consumer/Session were cached and not closed)

4. Questions:

a) Has anybody hit the same issue as us?

b) Would you consider this as a defect of Spring JMS for the use case of Non-Durable Subscriptions?

c) We are considering customizing a CachingConnectionFactory that won't stop the connection. Any downsides?

Note: We are aware that Async MessageListeners like DMLC/SMLC and Sync Durable Topic Subscribers using JMSTemplate would not have this issue. We just wish to clarify for Sync Non-Durable Topic Subscribers using JMSTemplate.

Would greatly appreciate any comments and thoughts.

Thanks!

Victor

Victor Lim
  • 21
  • 2

0 Answers0