Why is the message again coming to onMessage() function?
Asked Answered
K

5

9

I am using ActiveMQ to send the message.

So when I sent a message, the message comes to receive message. On successful insertion, it is acknowledged.

But I have code after acknowledgement, which can throw NullPointerException.

So to produce that exception intentionally, I have thrown NullPointerException. So when it does that:

Message is not dequeued and the same message comes again to the onMessage function.

My code is:

public void onMessage(Message message) {
    String msg = null;
    try
    {
        msg = receiveMessage(message);

        // Other code to insert message in db

        message.acknowledge();

        if(true)
        {
            throw new NullPointerException("npe"));
        }
            ** // Other code which might produce a null pointer exception **
        }
        catch(Exception ex)
        {
        }
    }

Why is the message again coming to onMessage() function as I have acknowledge() it also.

Since I have already inserted the message in db.

Doesn't the message inside queue will be removed on acknowledge()?

How I can achieve this?

Koeppel answered 14/9, 2012 at 12:14 Comment(6)
What is the acknowlge mode of your session?Forrestforrester
@Tim acknowlge mode is set as Client_Acknowledge. <property name="sessionAcknowledgeModeName" value="CLIENT_ACKNOWLEDGE"/>Koeppel
What version of activemq are you using?Forrestforrester
Version is : apache-activemq-5.6.0Koeppel
@TimBish I am still looking for an answer. Please let me know if you know the answer.Koeppel
You need to publish a better code snippet showing a more complete onMessage function and the connection creation and session creation along with the URI options etc. The provided example is to incomplete to know for sure. A full JUnit test would be ideal.Forrestforrester
H
2

You can create a separate method for processing the message, by which I mean that in the onMessage() function write code for only insertion of that message into the database.

And create a separate function for the processing of that message.

So that if you get any error during processing, the message will not come to onMessage() again.

Hydantoin answered 24/9, 2012 at 15:8 Comment(1)
Thanks for the idea.I will try to implenment it.Koeppel
P
4

You use AUTO acknowledge mode with message listners, then by specification, a message is redelivered if the message listeners fails to return successfully (for instance if there is an exception thrown).

In your case, you are trying to manually acknowledge the message, but that is not possible using a session created with createSession(false, Session.AUTO_ACKNOWLEDGE).

Your code would have worked with Session.CLIENT_ACKNOWLEDGE.

Otherwise, you want to catch the exceptions inside the onMessage method, while using AUTO_ACKNOWLEDGE.

To get a more fine grained controll over your messages, please consider using transacted sessions and use session.commit(); to confirm a message has been read.

Perchloride answered 14/9, 2012 at 20:50 Comment(1)
In my jms-confif.xml file . I have set it to CLIENT_ACKNOWLEDGE but still the same problem.Koeppel
T
3

Have you checked that you are not using transacted sessions?. When using transacted sessions,the acknowledge mode is ignored, so:

  • Your message.acknowledge() would effectively be a no-op

  • Your uncaught exception would be triggering a "session rollback" when escaping your message listener, forcing redelivery of the message.

NOTE: Your published code has a catch (Exception ex) { }, so I don't know exactly how your exception escapes outside.

Turkish answered 18/9, 2012 at 21:29 Comment(3)
After acknowledge , it throws Nullpointerexception and then it goes to the catch block. After that message again comes to the onMessage() function.Koeppel
"Your message.acknowledge() would effectively be a no-op" What does no-op means?Koeppel
@Koeppel No-op means "No operation". It is a common term for some instruction that does nothing.Turkish
H
2

You can create a separate method for processing the message, by which I mean that in the onMessage() function write code for only insertion of that message into the database.

And create a separate function for the processing of that message.

So that if you get any error during processing, the message will not come to onMessage() again.

Hydantoin answered 24/9, 2012 at 15:8 Comment(1)
Thanks for the idea.I will try to implenment it.Koeppel
K
0

When you use a transacted JMS acknowledge mode, your message will be received by JMS-listener several times (in AMQ by default it is approximately eight) till be processed without exception or will be moved by JMS-container to DQL-queue. See Message Redelivery and DLQ Handling for details.

Managing transactions depends on the framework used by you. I prefer to use Spring Framework, so my Spring XML configuration is looks like:

<jms:listener-container container-type="default"
                        connection-factory="calendarConnectionFactory"
                        acknowledge="transacted"
                        destination-type="queue"
                        cache="consumer"
                        concurrency="1-5">
    <jms:listener destination="${jms.calendar.destination}" ref="calendarListener"/>
</jms:listener-container>

And the Java code of my message listener is

@Override
@Transactional(propagation = Propagation.REQUIRED,
               noRollbackFor =
                 {ClassCastException.class, IllegalArgumentException.class})
public void onMessage(Message message) {
 ....
}

So I can manage what exceptions will rollback the transaction or not.

Kila answered 14/9, 2012 at 15:51 Comment(0)
D
0

I noticed your same problem. A catch(Exception ex) in the onMessage catches all the exceptions but still the message is coming again and again on the onMessage.

Moving the catch(Exception ex) to another class and making onMessage "exceptions free" solved the problem.

Dorcy answered 27/8 at 10:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.