5 Replies Latest reply on Apr 22, 2010 10:33 AM by igorhvr

    Should I re-use JMS connections or not?

    igorhvr

      Hi,

       

         Summary: Creating JMS connections every time is seen as an anti-pattern, but when I  keep my connections open for a long time they end up being closed  automatically with an error message. I need help to figure out what am I missing / what I should do...

       

         The details:

       

         According to the user manual and to a post I found, re-creating JMS connections (and sessions, message producers, etc) for every message is an anti-pattern:

       

           http://hornetq.sourceforge.net/docs/hornetq-2.0.0.GA/user-manual/en/html_single/index.html#d0e10827

           http://community.jboss.org/wiki/ShouldIcacheJMSconnectionsandJMSsessions

       

         On the other hand, I am receiving error messages such as:

       

           "WARNING: I'm closing a  JMS connection you left open. Please make sure you close all JMS  connections explicitly before letting them go out of scope!"

       

          after some time. I have a stand-alone application (outside JBoss or any application server) that uses HornetQ[1].

       

          Searching for the error message above lead me to the following post:

       

              http://community.jboss.org/message/532379#532379

       

         Where Tim Fox stated:

       

          "This isn't really relevant for  HornetQ. All  HornetQ connections created from a specific ConnectionFactory share the  same TCP connection (assuming you're using core protocol) anyway. Limiting  yourself to just one JMS connection is unnecessary."

       

         So... what is the recommended way of dealing with this?

       

      Regards,

      Igor.

       

      [1]. This is how I am retrieving a connection factory:

      private static ConnectionFactory getHornetqConnectionFactory(String hostname, int port) {

       

              Map<String, Object> connectionParams = new HashMap<String, Object>();

       

              connectionParams.put(TransportConstants.PORT_PROP_NAME, port);
              connectionParams.put(TransportConstants.HOST_PROP_NAME, hostname);

       

              TransportConfiguration transportConfiguration = new TransportConfiguration(NettyConnectorFactory.class.getName(),
                      connectionParams);

       


              HornetQConnectionFactory cf = (HornetQConnectionFactory) HornetQJMSClient.createConnectionFactory(transportConfiguration);


              cf.setReconnectAttempts(-1); // Never gives up.
              cf.setRetryInterval(1000); // Time to wait in milliseconds.

       

              return cf;
          }

        • 1. Re: Should I re-use JMS connections or not?
          jmesnil

          Igor HVR wrote:

           

               "WARNING: I'm closing a  JMS connection you left open. Please make sure you close all JMS  connections explicitly before letting them go out of scope!"

           

          This message means that your JMS Connection has been garbage collected before it was properly closed.

           

          You should check you app to be sure that:

          1. JMS connections are properly closed during your application lifecycle

          2. you do not leak JMS connections

          1 of 1 people found this helpful
          • 2. Re: Should I re-use JMS connections or not?
            leosbitto

            You must keep a strong reference to the Connection which you get by calling the method createConnection of ConnectionFactory. It seems that you lose that reference, which enables garbage collector to do its work...

            1 of 1 people found this helpful
            • 4. Re: Should I re-use JMS connections or not?
              leosbitto

              You must keep a strong reference to the Connection which you get by calling the method createConnection of ConnectionFactory. It seems that you lose that reference, which enables garbage collector to do its work...

               

              Just a wild guess: you create ConnectionFactory, then create Connection, then create Session, then create MessageProducer(s) and use only the MessageProducer(s) to send messages. You keep reference(s) only to the MessageProducer(s). With HornetQ, this setup makes ConnectionFactory, Connection and Session eligible for garbage collecting, because MessageProducer does not hold any reference to them. With other JMS providers it might not be so. Anyway, you should always keep reference to Connection to be able to call connection.close() when you are done!

              • 5. Re: Should I re-use JMS connections or not?
                igorhvr

                Hi - thanks for all the helpful responses.

                 

                It seems the problem really was that I was holding a reference to the message producer I was using, but letting go of the other objects (Session/Connection) I didn't need.

                 

                The problem seems to be solved by using thread-local instances of those objects:

                 

                Here is the code that creates the thread-local variables:

                 

                public static ThreadLocal createThreadLocalJmsConnection(final ConnectionFactory connectionFactory) {
                        return new ThreadLocal() {
                            public Connection result;

                 

                            protected synchronized Object initialValue() {
                                try {
                                    // Returns a javax.jms.Connection object.
                                    result = connectionFactory.createConnection();
                                    result.start();
                                    return result;
                                } catch (JMSException e) {
                                    throw new RuntimeException(e);
                                }
                            }

                 

                            protected void finalize() throws Throwable {
                                if(result!=null) result.close();
                            }
                        };
                    }

                 

                    public static ThreadLocal createThreadLocalJmsSession(final ThreadLocal connection) {
                        return new ThreadLocal() {
                            public Session result;

                 

                            protected synchronized Object initialValue() {
                                try {
                                    // Returns a javax.jms.Session object.
                                    result = ((javax.jms.Connection)connection.get()).createSession(false, Session.AUTO_ACKNOWLEDGE);
                                    return result;
                                } catch (JMSException e) {
                                    throw new RuntimeException(e);
                                }
                            }

                 

                            protected void finalize() throws Throwable {
                                if(result!=null) result.close();
                            }
                        };
                    }

                 

                    public static ThreadLocal createThreadLocalJmsMessageProducer(final ThreadLocal s, final String queueName) {
                        return new ThreadLocal() {
                            public MessageProducer result;

                 


                            protected synchronized Object initialValue() {
                                try {

                 

                                    Session session = (Session) s.get();
                                    Destination destination = session.createQueue(queueName);
                                    MessageProducer producer = session.createProducer(destination);
                                    producer.setDeliveryMode(DeliveryMode.PERSISTENT);
                                    result=producer;

                 

                                    // Returns a javax.jms.MessageProducer object.
                                    return result;
                                } catch (JMSException e) {
                                    throw new RuntimeException(e);
                                }
                                }
                            }

                 

                            protected void finalize() throws Throwable {
                                if(result!=null) result.close();
                            }
                        };
                    }

                 


                ... at some other point ...


                        threadLocalJmsConnection=createThreadLocalJmsConnection(connectionFactory);
                        threadLocalJmsSession=createThreadLocalJmsSession(threadLocalJmsConnection);
                        threadLocalJmsProducer=createThreadLocalJmsMessageProducer(threadLocalJmsSession, subject);

                 

                ...and finally, to actually use the session and producer:

                 

                            session = (Session) threadLocalJmsSession.get();
                            producer = (MessageProducer) threadLocalJmsProducer.get();