JMS Connection Pooling in Message Listener - java

Currently i'm working on a standalone Java apps that connects to a Websphere MQ to send and receive messages.
The flow is in asynchronous mode, which we implemented using MessageListener class to retrieve the messages from the queue when they are ready. The code to initialize the consumer with the listener is as follow:
if(connection == null)
connection = getJmsConnection();
try {
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
if (isTopic) {
destination = session.createTopic(destinationName);
} else {
destination = session.createQueue(destinationName);
}
consumer = session.createConsumer(destination);
consumer.setMessageListener(listener);
} catch (JMSException e) {
e.printStackTrace();
}
The getJmsConnection() method will return a connection from a pool, implemented using Apache Commons Pool library.
My question is, will the connection assign to the listener from the pool be active and tied to that listener as long as the program is running? Or the connection is used intermittently and can be reuse by other processes? Our idea is to have the sending and receiving process to reuse the connection from the pool, but i'm not sure how the MessageListener deal with the connection they are assigned with.
Thank you.

The key object here is the session rather than the connection; the session is on the one that will be doing the primary work here with the message consumption (async or otherwise).
It is advisable to try and share out the connection as widely as possible. Temporary destinations are scoped on the connection level. So the use of pooling is a good idea; it will be perfectly possible to share that connection around.
However I would also say that it might be worth considering pooling the sessions. With the code here a new session will be created, each time through that code, that will mean a new connection to the WebSphere MQ queue manager will be created. It's not clear what the scope of that will be, but if that is closed quickly it could become a bottleneck.

Related

Automatically reconnect Storm Topology to Redis Cluster on Redis restart

I have created a Storm topology which connects to Redis Cluster using Jedis library. Storm component always expects that Redis is up and running and only then it connects to Redis and subscribes the events.Currently we use pub-sub strategy of Redis.
Below is the code sample that explains my Jedis Connectivity inside Storm to for Redis.
try {
jedis.psubscribe(listener, pattern);
} catch(Exception ex) {
//catch statement here.
} finally {
pool.returnResource(jedis);
}
....
pool = new JedisPool(new JedisPoolConfig(), host, port); //redis host port
ListenerThread listener = new ListenerThread(queue, pool, pattern);
listener.start();
EXPECTED BEHAVIOUR
Once Redis dies and comes back online, Storm is expected to identify the status of Redis. It must not need a restart in case when Redis die and come online.
ACTUAL BEHAVIOUR
Once Redis restarts due to any reason, I always have to restart the Storm topology as well and only then it starts listening back to Redis.
QUESTION
How can I make Storm listen and reconnect to Redis again after Redis is restarted? any guidance would be appreciated, viz. docs, forum answer.
Catch the exception for the connection lost error and set the pool to null
(Assume that you doing this in Spout) Use an if-else statement to check if pool is null then create a new instance of JedisPool() assigning to the pool like in your code:
pool = new JedisPool(new JedisPoolConfig(), host, port); //redis host port
If pool not null (means connected) then continue your work
This is a common issue with apache-storm where connection thread is alivein stale condition, although the source from where you are consuming is down/restarted. Ideally it should retry to create new connection thread instead reusing the existing one. Hence the Idea is to have it automated it by by detecting the Exception (e.g. JMSConnectionError in case of JMS).
refer this Failover Consumer Example which will give you brief idea what to do in such cases.(P.S this is JMS which would be JMS in redis your case.)
The Steps would be something like this.
Catch Exception in case of ERROR or connection lost.
Init connection (if not voluntarily closed by program) from catch.
If Exception got to step 1.

IBM MQ : Any way to get connection interruption notification?

I am using IBM MQ-7.5. I am running a jms client which connects to the manager running on some other hosts.
I want to monitor the TCP connections with the manager. How do I get notified if my client connection is broken with the manager ? Is there any callback or listener provided in IBM MQ APIs to know any interruption on connection ?
Eg. Like ActiveMQ has http://activemq.apache.org/maven/apidocs/org/apache/activemq/transport/TransportListener.html
Thanks,
Anuj
In terms of connections being dropped a connection broken exception will be sent via the exception listener.
The JMS Specification is written such that events such as connection broken are legitimately returned on synchronous calls only. I would also recommended setting an exception listener, and to catch exceptions from all messaging operations and taking appropriate action.
Do you want to monitor client application connections at the queue manager end or in the client application?
To get notified of any connection issues, MQ JMS client has an ExceptionListener that can be attached to MQConnection. This exception listener will be invoked when there is an issue with connection to queue manager, for example connection to queue manager is broken. More details here: View details of setExceptionListener method. Call the setExceptionListener method on MQConnection to register a callback as shown below.
MQQueueConnectionFactory cf = new MQQueueConnectionFactory();
ExceptionListener exceptionListener = new ExceptionListener(){
#Override
public void onException(JMSException e) {
System.out.println(e);
if(e.getLinkedException() != null)
System.out.println(e.getLinkedException());
}
};
MQQueueConnection connection = (MQQueueConnection) cf.createQueueConnection();
connection.setExceptionListener(exceptionListener);
To actively check the health of connection and session, i am thinking of using below approach.
/**
* Method to check if connection is healthy or not.
* It creates a session and close it. mqQueueConnection
* is the connection for which we want to check the health.
*/
protected boolean isConnectionHealthy()
{
try {
Session session = mqQueueConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
session.close();
}
catch(JMSException e) {
LOG.warn("Exception occured while checking health of connection. Not able to create " + "new session" + e.getMessage(), e);
return false;
}
return true;
}
/**
* Method to check if session is healthy or not.
* It creates a consumer and close it. mqQueueSession
* is the session for which we want to check the health.
*/
protected boolean isSessionHealthy()
{
try {
MessageConsumer consumer = mqQueueSession.createConsumer(mqQueue);
consumer.close();
}
catch(JMSException e) {
LOG.warn("Exception occured while checking health of the session. Not able to create "
+ "new consumer" + e.getMessage(), e);
return false;
}
return true;
}
Does it approach looks good ?
I just have one fear here:
I am creating a test session in isConnectionhealthy() method and closing it. Will it not affect the already created session which is actually used for real communication? I mean will it do something like it closed already created session and started new one ?

JMS Message Sending After JMS Server Restart During Runtime

I am having a problem about JMS. The problem is, I have an application and it is trying to send a message through JMS , but after JMS server restart, it throws exception as when the server was down time. It is not reconnecting.
It is completely fine without a restart of JMS server and I am using weblogic 10.x.
Is it a problem about JMS configuration?
Thanks
Can you post your code how you are sending messages?
If you attempt to send a message when the JMS server is down, you will probably have an exception, and have to deal with that. When you attempt to send a message the next time, when the JMS server is restarted and running, you probably create a new connection from your connection factory. Reconnection will happend then:
// Let's say, you inject CF and Dest.
#Resource(lookup = "jms/ConnectionFactory")
private static ConnectionFactory cf;
#Resource(lookup = "jms/MyQueue")
private static Destination dest;
public void sendMessage(){ // called every time you need to send a message.
try{
Connection con = cf.createConnection(); // will reconnect, otherwise pooled.
Session sess = con.createSession(false,Session.AUTO_ACKNOWLEDGE);
MessageProducer prod = sess.createProducer(dest);
Message msg = sess.createTextMessage("Hello, World");
prod.send(msg);
sess.close();
con.close();
}catch(Exception e){
// handle errors
}
}
However, there are some built in failover/reconnecting features in Weblogic JMS, take a look at this page:
Oracle code listing and documentation about reconnecting JMS producers

Simple JMS Clients on OS X

I haven't touched any J2EE stuff in years and I need to whip up a quick JMS client for a demo.
I'm using Eclipse, on OS X and I can't even get started because I can't seem to figure out how to get the required libraries.
This is supposed to be a simple stand alone application (not running in a container) that pulls messages from a topic.
Every JMS implementation has its own set of libraries that specify how you get the initial connection factory. If you have an existing server from which to pull messages, you need to examine the documentation of that server to determine where to find the libraries to put in your classpath and how to create your initial connection factory. If you want to create a server for the purposes of the demonstration, I recommend using an embedded Active MQ broker.
Once you have your connection factory, polling for messages from a topic is pretty straightforward. Here is some example code which can be called to drain a topic of its current messages.
// Implementation specific code
public void drainTopic(TopicConnectionFactory factory, String topicName, String subscriberId)
// set factory properties like the server ID
Connection conn = factory.createConnection();
conn.start();
Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
Topic topic = session.createTopic(topicName);
MessageConsumer consumer = session.createDurableSubscriber(topic, subscriberId);
Message message;
while (null != (message = consumer.receive(1000))) {
// do work on the message
}
conn.close();
}
Note the use of a durable subscriber. This means that I don't have to try to maintain a single connection all the time and handle the errors if it times out somehow. But because the subscription is durable, the server knows to retain any messages the topic receives while I'm not connected and provide them on my next connection. This code would be the same regardless of the host OS. The only tricky part is the creation of the provider specific connection factory.

Long lived JMS sessions. Is Keeping JMS connections / JMS sessions always opened a bad practice?

Is keeping JMS connections / sessions / consumer always open a bad practice?
Code draft example:
// app startup code
ConnectionFactory cf = (ConnectionFactory)jndiContext.lookup(CF_JNDI_NAME);
Connection connection = cf.createConnection(user,pass);
Session session = connection.createSession(true,Session.TRANSACTIONAL);
MessageConsumer consumer = session.createConsumer(new Queue(queueName));
consumer.setMessageListener(new MyListener());
connection.start();
connection.setExceptionListener(new MyExceptionHandler()); // handle connection error
// ... Message are processed on MyListener asynchronously ...
// app shutdown code
consumer.close();
session.close();
connection.close();
Any suggestions to improve this pattern of JMS usage?
Agreed. Here are some good tips on how to use JMS efficiently which includes keeping around connections/sessions/producers/consumers.
You might also want to check the recommendation on using transactions too if you are interested in maximising performance.
That is a very common and acceptable practice when dealing with long lived connections. For many JMS servers it is in fact preferable to creating a new connection each time it is needed.
The choice of keeping connection/session/producer/consumer open for long or not should be based on the frequency at which producer/consumer sends/receives messages.
If a producer sends or a consumer receives messages frequently then the connections/sessions/producer/consumer should be kept open. On the other hand if messages send/receive is infrequent then it is not good keeping these JMS objects open will consume system resources like sockets.
In our app, we will have connections/sessions/consumers/producers open for months at a time. We've had to work with our vendor (BEA) to make that work reliably. But any troubles with that is a bug the vendor needs to fix.
FYI, there is no need to close the sessions, producers, and consumers of a closed connection( javax.jms.Connection ).
The code below should be enough to release the resources:
try {
this.connection.close();
} catch (JMSException e) {
//
}

Categories

Resources