camel, JMS, CLIENT_ACKNOWLEDGE mode - jms

I know that Camel's JMS component, for receiving messages, uses Springs DefaultMessageListenerContainer. It can be configured to use CLIENT_ACKNOWLEDGE mode for acknowledging messages. My question is, when exactly the message.acknowledge() method gets called? Is it called internally by the spring's listener container?
Or can I somehow acknowledge message at my will?
I'd like to avoid scenario that messages get lost because my app crashed during processing of these messages and making it transactional seems a bit too heavy for me

OK. After some some debugging and scanning throug source code I've found out that Camel uses spring MessageListenerContainers. The AbstractMessageListenerContainer, in case of CLIENT_AKNOWLEDGE mode, invokes comitIfNecessary method acknowledging message. This happens only AFTER registered MessageListener processes message succesfully (no exceptions)
Camel uses EndpointMessageListener which, eventually, invokes process method of next processor (or Producer) down the route. As this is classic chain of responsibilities, if any processor down the route throws exception or sets exception on the Exchange, it will be re-thrown by EndpointMessageListener preventing the AbstractMessageListener to acknowledge message.

Related

Spring JMS acknowledgement behavior with TIBCO EMS EXPLICIT_CLIENT_DUPS_OK_ACKNOWLEDGE

I am using Spring JMS with TIBCO EMS queue/topic for my spring boot application. The TIBCO EMS queue is setup with EXPLICIT_CLIENT_DUPS_OK_ACKNOWLEDGE. In my code, I am not setting the acknowledgment mode, so I assume spring will take it s default AUTO_ACKNOWLEDGE. The behavior I notice in my listener onMessage method is, if the application successfully process the message, no redelivery of the same message And if the application throws a RuntimeException, there is a redelivery of the same message. The code is also with setSessionTransacted to true with DefaultJmsListenerContainerFactory. In this scenario, is the spring actually acknowledging the message on my behalf or do the code need to set the message.acknowledge().
See the javadocs for Session. Auto means the provider library automatically acks the message when consumer.receive() returns it, or the consumer.messsageListener() exits.
With a SimpleMessageListenerContainer, your listener is called directly by the provider's Consumer so messages won't be auto-ack'd until your listener exits normally.
The DirectMessageListenerContainer calls receive() instead and calls your listener on its own thread. Hence we need transactions to roll back the ack after an exception is thrown.

When an Exception is thrown in a provider-side ActiveMq BrokerFilter send method, how can the JMS sender subscribe as listener to that exception?

We implemented a filter, or plugin, in ActiveMq broker that intercepts inbound messages and validates them from a security standpoint.
We are needing a programmer friendly way of receiving these exceptions on the producer side (ideally not at connection level, but at session or producer level, since they may need session specific reaction).
We are doing message level authorization in the broker side in the following way: In the ActiveMq provider (server) we implement BrokerFilter (plugin) in order to intercept the incoming JMS message, and validate a JWT access token attached to the message as property. If the JWT token is valid, then the message is let through downstream chain, if it is not valid, a SecurityException is thrown.
We notice that the message does reach back to the sending JVM which reports that no ExceptionListener instances registered for the specific exception.
Our question is, where can we best register an ExceptionListener in Spring JMS for this scenario? We have direct access to the producer and JMS session, but not to the JMS connection.
It is true that registering an ExceptionListener to the connection would be useful for connection level events, but for session level events it may make the code more understandable and cohesive if we could register such exception listeners locally to the session or producer, since they are kind of direct responses to a message send attempt.
Of course it would be also possible to implement local exception listeners via connection level and a thread local structure of local listeners, but i am wondering if JMS or Spring already provides such possibility of the session or producer finding out directly that their message was not authorized, so that they answer upstream to calling microservice rather then retyrying to send it for instance.
We are using persistent messages but unsure if we do synchronous or asynchronous send. I believe on asynchronous send, an ExceptionListener of some kind will be called back on such an event (exception thrown in BrokerFilter.send method). While on the synchronous send perhaps the exception will directly be thrown there (but the thread blocking may decrease robustness of the microservice).
This is solvable with connection.setExceptionListener but to us it would likely be more convenient a session.setExceptionListener or even a message request level listener.
We would like to see any other options possible with Spring JMS except registering an exception listener at connection level and except synchronous send, if any such other options are possible.
Since Spring JMS uses the JMS API then you're pretty much limited to what the JMS API provides and it doesn't provide a session or request level exception listener. It provides a connection level exception listener for exceptions which are reported asynchronously and normal Java checked exceptions for the synchronous use-case.

Integration with external systems over JMS. Clustered environment

I have an application where I created 2 message listener containers for external system A which listens two queues respectively.
Also I have 1 message listener container which running and listening another queue of external system B. I am using spring DefaultMessageListenerContainer.
My application is running on clustered environment, while defining my message listener container I injected to it my listener which implements javax MessageListener interface and acts as kind of MDB.
So my questions are:
Is it normal to have instance of message listener container per queue?
Will my message driven pojo (MDP) execute onMessage() on each application node?
If yes, how can I avoid it? I want each message to be consumed once on some of the application nodes.
What is default behavior of DefaultMessageListenerContainer, message is acknowledged as soon as I reached onMessage or after I finished execution of onMessage? Or maybe I need to acknowledge it manually?
See the spring framework JMS documentation and the JMS specification.
Yes it is normal - a container can only listen to one destination.
It depends on the destination type; for a topic, each instance will get a copy of the message; for a queue, multiple listeners (consumers) will compete for messages. This has nothing to do with Spring, it's the way JMS works.
See #2.
With the DMLC, it is acknowledged immediately before calling the container; set sessionTransacted = true so the ack is not committed until the listener exits. With a SimpleMessageListenerContainer, the message is ack'd when the listener exits. See the Javadocs for the DMLC and SMLC (as well as the abstract classes they subclass) for the differences.

about Session.rollBack() in JMS

All,
i am new to JMS and i have a question about Session.rollBack() method in JMS. AFAIK, this method is used to roll back all operations to JMS server (sending/receiving) by the session when using *SESSION_TRANSACTED* acknowledge mode. Now suppose I am calling this method in a catch block of a receiving/processing operation (is reasonable?), to tell JMS server to redeliver the message for processing, But even if it is redelivered the processing still throws the same exception which cause the JMS server to redeliver the message again, so it seems a infinite process. How to handle this problem? or are there any other JMS features that is designed for it? Thanks in advance!
The rollback method in JMS will rollback any message sends and receives in that "transaction". Transaction here is local to the JMS session.
Whether a redelivery will cause a problem really depends on why the exception occurred. If it was due to some transitory issue then a redelivery may work. If you have the kind of problem that is once it occurs will always occur (an example of this would be a JMS TextMessage whose body should contain XML, but doesn't).
The JMS API doesn't provide any solution to this itself. This is typically taken care of by the JMS provider and how it behaves will depend on which one you use. WebSphere MQ for instance will redeliver up to a configurable maximum at which point it will move it off to a queue for bad messages. The Service Integration Bus in WebSphere Application Server has similar behaviour. I suggest you consult your JMS provider documentation to determine exactly how it behaves in this situation.
If you are running in an application server rollback typically doesn't do anything because the application server will be managing transactions for you.

JBoss doesn't sends a JmsTemplate (Spring) message

Well, actually JBoss does send the message, but only when the current transaction started by the EJB is finished.
We have this problem with JBoss 4.0.3 and Spring's JmsTemplate. An EJB sends a message to a queue with a temporary queue as the reply_to field. Then, inside the same transaction, we listen for the response given by the first MDB. The problem is that the JmsTemplate's method "send" isn't executed after the transaction have finished. So, by the time the message is sent to the queue, and processed by the MDB, the listener of the temporary queue is gone.
This is called "Synchronous Reception"
Two things change this behavior but does raise some concerns:
Change the EJB's transaction type to BMT. (Concern: BMT sucks)
Create a thread that all it does is to call the JmsTemplate.send() method.
As a side note, this is an EJB that is working correctly on a weblogic environment, and the message does get sent when it should, in the middle of the transaction not when it's over.
Thanks for any help.
JBoss's behaviour is correct. JMS is a transactional API, and sends should only be executed when the tx commits.
It may be possible to convince JmsTemplate not use the current transactional context, although it makes a point of trying to hide the unpleasantness of the JMS API from you.
You could wrap the JMS template in code, either a Stateless session bean or a service method using Spring's transaction management, that uses a transaction propagation of REQUIRES_NEW. That way the sending of the message is in its own transaction that will commit the sending of the message outside the scope of the wrapping transaction.
I'm not sure why this would work on Weblogic though. My guess would be that on Weblogic it's not recognizing the queue as an XA Queue.

Resources