Spring JMS - redelivery by sending message back to same queue instead of rollback transaction

vortex.alex picture vortex.alex · Dec 4, 2013 · Viewed 9.4k times · Source

this is my first post here so I apologize in advance if I don't respect formatting rules or other general rules.

I have a Spring JMS based client application that reads from a queue using multiple consumers. My constraints are: guaranteed redelivery in case of failure and message duplication detection.

Spring configuration

<bean id="jndiDestinationResolver" class="org.springframework.jms.support.destination.DynamicDestinationResolver" />


    <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
        <constructor-arg ref="MyConnectionFactory" />
        <property name="destinationResolver" ref="jndiDestinationResolver" />
        <property name="receiveTimeout" value="100" />
    </bean>


    <bean class="org.springframework.jms.listener.DefaultMessageListenerContainer">
            <property name="destinationResolver" ref="jndiDestinationResolver" />
            <property name="connectionFactory" ref="MyConnectionFactory" />
            <property name="destinationName" value="my_Queue" />
            <property name="messageListener" ref="MyListener" />
            <property name="maxConcurrentConsumers" value="10"/>
            <property name="sessionTransacted" value="true"/>
    </bean>

My listener code is something like:


    protected void processTextMessage(TextMessage textMessage) {
        try {
            // process message
        } catch(Exception e) {
            try {
                sendTextMessage("my_Queue",correlationID, textMessage.getText());
            } catch (JMSException e1) {
                log.error("Error writing message back to the queue!");
                throw JmsUtils.convertJmsAccessException(e1);

            }
        }
    }


    protected void sendTextMessage(String queueName, final byte[] correlationID, String message) {
        jmsTemplate.convertAndSend(queueName, message, new MessagePostProcessor() {
            public Message postProcessMessage(Message message) throws JMSException {
                message.setJMSCorrelationIDAsBytes(correlationID);
                return message;
            }
        });
    }

I made some local failure tests with ActiveMQ and re-sendings were ok (I noticed the redelivered flag to false). I also tried to stop brutally the application server during processing, and was able to check in that moment queue contained 1 message with redelivered=true.

Would this be a right approach to reach my goals?

I hope this would be transparent in respect to the JMS provider i will use (on production environents Websphere MQ is used). At the moment I would like to avoid just rollback the transaction by throwing an exception: i wish to reschedule my failed message like a new fresh message in the queue. For duplicate detection, I think inserting a business existence check would be enough.

Thanks in advance and best regards

Answer

Gary Russell picture Gary Russell · Dec 4, 2013

Yes, that is the correct approach.