Question

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

Was it helpful?

Solution

Yes, that is the correct approach.

OTHER TIPS

It may be a better approach to have an ERROR queue in addition to the current(SUBMIT) queue.

A few reasons:

  1. Better analysis of error messages in case of invalid information from source. You can have a MSG_PROCESSED_CNT property on the message header and use it to reprocess the message as needed. It's useful when you have external integration in your business logic.

  2. What happens if your code [try-block] repeatedly throws an exception due to a bug or integration issue? Using an ERROR queue, you would see a rise in the depth and can notified of the issue by setting up a threshold monitor.

  3. Delegating the reprocess work (non-business related) to a third-party app. Your code would just contain your business logic.

if you republish to the same queue. you might endup processing same packet again and again. instead you can have move them to an error queue or retry queue on failure.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top