Search code examples
jmsactivemq-classicdead-letter

How to close JMS Connection properly


I have the following piece of code to poll my Dead Letter Queue in JMS.

Message  m = mconsumer.receive(3000L);
      while (m != null) {
        try {
          sendMessageToDB(m);   
        } catch (DBException ex) {
          writeToDeadLetterQueueBack(m);
        } 
       m = messageConsumer.receive(3000L);
      }

Now inside this while loop if a DBException occurs my connection does not get closed, and if my close the connection inside the catch block, the following line will fail as session is closed now .

m = messageConsumer.receive(3000L);

How to deal with this.


Solution

  • It is generally accepted best practice not to 'write-back' the message to the dead letter queue, but rather 'roll it back' using a transacted session.

    In your design, you'll have an infinite loop of constantly consuming and pre-publishing messages back to the Dead Letter Queue in the event of a DB outage. You'd be best to kick this thing off on a timer (run hourly, etc).. or have it have some sort of back off logic to stop constantly polling the DLQ during error scenario.

    General session-based one-message-at-a-time commit and rollback handling w/ proper object close routine in finally block.

    Session session = connection.createSession(true, Session.TRANSACTED);
    MessageConsumer consumer = session.createConsumer(session.createQueue('MY.QUEUE.DLQ');
    
    Message  m = mconsumer.receive(3000L);
      while (m != null) {
        try {
          sendMessageToDB(m);
          session.commit();
          m = messageConsumer.receive(3000L);
        } catch (DBException ex) {
          session.rollback();
          logger.error("Rolling back messageId {} due to database error {}", m.getJMSMessageId(), ex);
        } finally {
          if(consumer != null) {
              try { consumer.close(); } catch (JMSException e) { logger.error("Error closing consumer.."); } 
          }
          if(session != null) {
              try { session.close(); } catch (JMSException e) { logger.error("Error closing session.."); } 
          }
          if(connection != null) {
              try { connection.close(); } catch (JMSException e) { logger.error("Error closing connection.."); } 
          }
        }
      }