Spring JMS listener acknowledging even when exception
Asked Answered
S

2

9

I am using JMS to send/receive messages to my SQS queue, however i am unable to redeliver the message when there is an exception even while using client_acknowledge. How to achieve this? I tried a simple test,

@JmsListener(destination = "test-normalqueue")
public void receiveNormalQueue(String message)
{

    try {
        logger.info("message received in normal queue: " + message);
        throw new NullPointerException();

    } catch (Exception e) {

        logger.error(LoggingUtil.getStackTrace(e));;
    }

}

Even after exception message doesnt come back to queue.

@Bean
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() {
    DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
    factory.setConnectionFactory(getSQSConnectionFactory());
    factory.setConcurrency("1-2");
    factory.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
    return factory;
}
Striking answered 6/5, 2017 at 6:17 Comment(4)
There is no exception. You are catching everything. Spring needs to see an exception to rollback/ not acknowledge it but as you are catching it (and swallowing) spring thinks everything is ok.Conure
Hi, Thanks for clarifying. But i have one doubt in this approach, if i throw the exception, message will be re queued, but then listener will again pull it back and will again throw exception forming a loop, how do i handle this case?Striking
That is something you want to handle at your broker (I'm not that familiar with the SQS options) but generally you can configure a number of times a message is re-delivered and afterwards either discarded or moved to a different channel/queue.Conure
Thank you for the explanation, i just looked up and saw DLQ in SQS are for the exact same purpose.Striking
T
8

You have to use transactions with the DMLC.

Use Session.AUTO_ACKNOWLEDGE and setSessionTransacted(true).

If the listener exits normally, the message is removed. If the listener throws an exception, the message will be rolled-back onto the queue.

You can also use client mode with transactions, but you have to acknowledge successful messages yourself.

You don't have to use transactions with a SimpleMessageListenerContainer but you still have to throw an exception to get the message requeued.

Trug answered 6/5, 2017 at 13:29 Comment(2)
Hi, I tried using SMLC, but it doesnt work, can you please take a look at #43806323Striking
Setting the session to AUTO_ACKNOWLEDGE and the sessionTransacted to true worked for meLebna
L
0

The Messages comes back to queue only if the listener stops and disconnects from the broker, the behavior you are describing is on the client side on the DefaultMessageListenerContainer which dispatch messages to your listener and manage exceptions and retries, the broker is not aware of those treatments and he only knows that these messages are dispatched to the client and is waiting acknowledgements. It is depends on the SQS methods and capabilities if there a method like reset or restart on the implementation of MessageConsumer. You can try recover() method of jms session but i think this will only restart delivery on the client side. https://docs.oracle.com/javaee/7/api/javax/jms/Session.html#recover--

This is a not good practice but if you restart the connection or the DefaultMessageListenerContainer the messages not acknowledged comes back to broker and the delivery restarts.

Letters answered 6/5, 2017 at 8:50 Comment(4)
I dont quite understand, what is the broker here? and how do you want me to solve this? Is there anyway, we can do it with jmslistener?Striking
The broker here is SQS since it exposes a JMS interface. The principle of JMS is that the client have to treat the message, can you explain why you want the message to comes back to queueLetters
You said ** i am unable to redeliver the message when there is an exception** since you are catching the Exception it is normal that the message is considered as consumed and not redelivered, if you want the message to be redelivered to the listener you have to throw the exception after logging itLetters
Hi, Thanks for clarifying. But i have one doubt in this approach, if i throw the exception, message will be re queued, but then listener will again pull it back and will again throw exception forming a loop, how do i handle this case?Striking

© 2022 - 2024 — McMap. All rights reserved.