I am using ActiveMQ to enqueue email messages, the consumer reads the queue and sends out emails.
At startup, I register a producer and cache it forever.
PooledConnectionFactory factory = new PooledConnectionFactory(new ActiveMQConnectionFactory(jmsBrokerUserName, jmsBrokerPassword, activeMQBrokerURL)); Connection connection = factory.createConnection(); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); Destination destination = session.createQueue(queueName); MessageProducer producer = session.createProducer(destination);
From time to time, the producer fails to enqueue the message as the connection gets closed.
Caused by: javax.jms.IllegalStateException: The Session is closed at org.apache.activemq.ActiveMQSession.checkClosed(ActiveMQSession.java:767) ~[activemq-client-5.10.0.jar:5.10.0] at org.apache.activemq.ActiveMQSession.configureMessage(ActiveMQSession.java:755) ~[activemq-client-5.10.0.jar:5.10.0] at org.apache.activemq.ActiveMQSession.createTextMessage(ActiveMQSession.java:438) ~[activemq-client-5.10.0.jar:5.10.0] at org.apache.activemq.jms.pool.PooledSession.createTextMessage(PooledSession.java:242) ~[activemq-jms-pool-5.10.0.jar:5.10.0]
Can somebody please let me know what is the best way to handle closed sessions? Should I re-register my producer? Or is there a way to reopen session?
When using JMS you shouldn't really cache the JMS Session (and anything hanging of that such as a Producer). The reason being is that the JMS Session is the unit of work within JMS and so should be a short lived object. In the Java EE world that JMS Session might also be enlisted with a global transaction for example and so needs to be scoped correctly.
The JMS Session instance can not be used concurrently by multiple threads, so the best advise is to create the JMS Session on each thread you are using and close the jms session when you have finished that unit of work (sending a message or a collection of messages in a transaction)