1

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.

station
  • 6,715
  • 14
  • 55
  • 89

1 Answers1

1

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.."); } 
      }
    }
  }
Matt Pavlovich
  • 4,087
  • 1
  • 9
  • 17
  • What will happen in case of rollback from DLQ . Will the message be rolled back to main queue. – station Jun 26 '18 at 06:44
  • When you do a rollback() the broker is informed that the consumer is not accepting the message. The broker then keeps it in the queue. Generally (depending on the destination policy in ActiveMQ), after a certain number of delivery attempts to a consumer, the broker will move the message to a dead letter queue, or discarded. In the example above, I'm showing you how to shut the connection down, so you don't get repeated redeliveries. The approach above would work well as a triggered scheduled job to clear out messages from a Dead Letter Queue, but not as an "always on service". – Matt Pavlovich Jun 27 '18 at 02:41