Spring JMS Consumers to a TIBCO EMS Server expire on their own - spring-boot

We have built a Spring Boot messaging service that listens to a JMS queue hosted on a TIBCO EMS (Enterprise Messaging Service) Server. It is a fairly straightforward application that receives a JMS message, does some data manipulation and updates a database.
The issue is that, occasionally, there are no JMS consumers on the queue, and incoming messages are not processed. However the Spring Boot app is up and running (verified by ps -ef). Restarting the app restores the consumer, but unfortunately this is not a feasible solution in production etc.
Other facts of interest:
We have observed this to happen when the JMS server accepts SSL traffic and is on deployed as a Fault Tolerant pair (although this has been a conculsive observation yet)
There is absolutely no indication in the log (like an error) when the consumer goes down.
We are using Spring-JMS (4.1.0) and TIBCO EMS (8.3.0)
Code Snippet of instantiating a DefaultJmsListenerContainerFactory:
#Bean
public DefaultJmsListenerContainerFactory listenerJmsContainerFactory() {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
TibjmsQueueConnectionFactory cf = new TibjmsQueueConnectionFactory("tcp://localhost:7222");
cf.setUserName("admin");
cf.setUserPassword("");
factory.setConnectionFactory(cf);
return factory;
}
The JMS Listener:
#JmsListener(destination = "queue.sample", containerFactory = "listenerJmsContainerFactory")
public void listen(TextMessage message, Session session) throws JMSException{
System.out.println("Received Message: "+message.getJMSMessageID());
System.out.println("Acknowledgement Mode: "+session.getAcknowledgeMode());
// Some more application specific stuff
}
While we are trying to setup additional logging on both the Spring Boot and TIBCO side, we would like to check some points like:
Can there be a situation where a consumer idle for more than a certain time, automatically expires?
Is this something that is governed by DMLC settings like idleConsumerLimit, idleTaskExecutionLimit etc.?
Can these properties be viewed in the Spring Boot code mentioned above? For instance in the code above, the JMS Listener is being created under the hood by the DefaultJmsListenerContainerFactory. So how can we access the DMLC object so that we can invoke methods like getIdleConsumerLimit(), getIdleTaskExecutionLimit() etc.
Thanks for the inputs,
Prabal

Most likely, something in the network (router, firewall etc) is silently dropping idle connections.
While not part of the JMS spec, most vendors implement some kind of heartbeat mechanism so that the client/server exchange pings from time to time, to prevent such actions by network components and/or to detect such conditions.
Look at the Tibco documentation to figure out how to configure heartbeats (they might call it something else).

Related

Performance issues with ActiveMQ Artemis and Spring JmsTemplate

While doing some load tests with the ActiveMQ Artemis broker and my Spring Boot application I am getting into performance issues.
What I am doing is, sending e.g. 12,000 messages per second to the broker with JMSeter and the application receives them and saves them to a DB. That works fine. But when I extend my application by a filter mechanism, which forwards events after saving to DB, back to the broker using jmsTemplate.send(destination, messageCreator) it goes very slow.
I first used ActiveMQ 5.x and there this mechanism works fine. There you could configure the ActiveMQConnectionFactory with setAsyncSend(true) to tune performance. For the ActiveMQ Artemis ConnectionFactory implementation there is no such a possibility. Is there another way to tune performance like in ActiveMQ 5.x?
I am using Apache ActiveMQ Artemis 2.16.0 (but also tried 2.15.0), artemis-jms-client 2.6.4, and Spring Boot 1.5.16.RELEASE.
The first thing to note is that you need to be very careful when using Spring's JmsTemplate to send messages as it employs a well-known anti-pattern that can really kill performance. It will actually create a new JMS connection, session, and producer for every message it sends. I recommend you use a connection pool like this one which is based on the ActiveMQ 5.x connection pool implementation but now supports JMS 2. For additional details about the danger of using JmsTemplate see the ActiveMQ documentation. This is also discussed in an article from Pivotal (i.e. the "owners" of Spring).
The second point here is that you can tune if persistent JMS messages are sent synchronously or not using the blockOnDurableSend URL property, e.g.:
tcp://localhost:61616?blockOnDurableSend=false
This will ensure that persistent JMS messages are sent asynchronously. This is discussed further in the ActiveMQ Artemis documentation.

Trying to redesign JMS configuration as Spring Integration: Redelivery policies

My legacy configuration exposes a ConnectionFactory #Bean of type ActiveMQConnectionFactory, with custom redelivery through activeMQConnectionFactory.setRedeliveryPolicy(..).
I found out that Spring Integration DSL allows redeliveries on the handle operation as well by means of RequestHandlerRetryAdvice, which can be configured for instance with an ExponentialBackOffPolicy.
I am wondering if they are triggering the same code at the lower level (not sure its a client thing or a signaling thing to the broker), and if not, whether they are equivalent and whether can I safely replace the abstract version without missing any configuratbility
No; it's completely different and has nothing to do with JMS and retrying incoming deliveries.
The retry advice is generally used to retry outgoing requests, e.g. an http request, or a send to JMS.

Use SimpMessagingTemplate without creating a web socket message broker Spring 4

Can I send a message to a message broker using SimpMessagingTemplate#convertAndSendToUser or SimpMessagingTemplate#convertAndSend methods without settings up a websocket message broker using #EnableWebSocketMessageBroker?
What I'm trying to do is utilise one websocket server to provide messaging for two application server instances(One spring 4 and one Spring 3). I created a one web server with Spring 4, Spring boot plus websocket message broker enabled.
Now I want two application servers to push messages to rabbitmq so it will broadcast them to clients subscribed to it.
First issue I faced is if there is no websockt message broker configuration available, SimpMessagingTemplate will not get autowired to application context. I couldn't get it injected without creating a websocket message board either.
Please help me to find out whether this is possible.
BTW I have a previous question unanswered related to this.
Well, After reading lots of documentation I found the answer myself. The key thing is this architecture is following.
In this architecture spring act as a gateway for communication between the message broker and client. Spring doesn't do anything(Other than when it necessary) but forward the request to the message broker(STOMP messages). The configuration kept on Spring defines couple of important things. One is the exchange and other were routing keys. Spring configuration gives us an abstract layer so we subscribe and push messages to message broker without a fuss.
SimpMessagingTemplate is the abstract layer which we use to communicate with message broker. Spring creates the bean using the given details. Well I couldn't create a instance of SimpMessagingTemplate manually. I have to update Spring 3 application to Spring 4 in order to use websockets.
Since Spring and message broker is decoupled, clustering the application instance doesn't make any effect on message broker. Spring will communicate to message broker only when it need to subscribe to a channel or when it need to publish a message to a channel. So if there is two instances subscribing to same channel it would be two queues binding the one exchange using same routing key. Messages published into a channel will be available to all subscribers(queues) because they all use same routing key. Refer to rabbitmq stop plugin documentation for more elaborative description.

How to get properly all queue messages from RabbitMQ in Spring?

I am using Spring, Spring-Websocket, STOMP for my application, and RabbitMQ as broker. I need to log all messages going through RabbitMQ to Postgresql tables.
I know that I can write #MessageMapping in Spring and log there, but my problem is that some clients talk to RabbitMQ directly through MQTT protocol, and Spring does not support it yet (https://jira.spring.io/browse/SPR-12581). Moreover browser clients talk through Spring to RabbitMQ using STOMP protocol.
RabbitMQ allows to track all messages using Firehose tracer. How to properly listen to amq.rabbitmq.trace topic from Spring? Or do I need to write separate Java app as consumer?
The Spring AMQP is for you!
You bind some custom queue to to that amq.rabbitmq.trace with appropriate pattern (e.g. publish.#) and configure SimpleMessageListenerContainer to receive messages from that queue.
It can be done even with pretty simple config: #EnableRabbit and #RabbitListener on some POJO method. Anyway the Binding #Bean must be there to attache your queue to that exchange.

More than one JMS ConnectionFactory

I am new to JMS and currently developing a simple Chat application explained in Oreilly 'Java Message service'. I've configured a TopicConnectionFactory in ActiveMQ that receives chat messages from TopicPublishers and dispatch that to TopicSubscribers.
My question is 'why do we need to create more than one TopicConnectionFactory' in any JMS application? Since Connectionfactory instances are not tied up with a Topic/Queue, why can't we use one instance of ConnectionFactory for creating connections to all the Topics (or Queues) configured in an application?
Technically speaking you are right. You may be able just to use one ConnectionFactory.
However it is a better design to use multiple ConnectionFactories depending on your requirements so the traffic would be spread out evenly and you do not run out of connections.
So if you know about a JMS Client application that may be problematic (the logic does not allow proper connection handling open/close), you may isolate it to use its own connection factory.
Also some connection factories allow a pool of 10 default active connections at the same time (it depends on the implementation/ settings) if you will need more you may use more than one connection factory.
I've configured a TopicConnectionFactory in ActiveMQ that receives chat messages from TopicPublishers and dispatch that to TopicSubscribers.
Very ambiguous statement. TopicConnectionFactory does not receive or send any messages. It is just one of the admin Objects used to create Connection which in turn creates Session which in turn creates your publishers and subscribers which publish and subscribe the messages.
why can't we use one instance of ConnectionFactory for creating connections to all the Topics (or Queues) configured in an application?
You definitely can. There is no one stopping you from doing that.
As per specs
A connection factory object encapsulates a set of connection configuration
parameters that has been defined by an administrator. A client uses it to
create a connection with a JMS provider.
So unless you have different configuration requirements you can use same ConnectionFactory to create multiple Connections. And yes as otc has mentioned above number of connections is one of the configuration parameter.

Resources