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.
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.."); }
}
}
}