handle over exception in JMS operations - jms

I am using activeMQ 5.4 for JMS implementation in my project.
I want to notify user every time application fails to send a message
but I am not getting any handle at occurrence of an exception.
For instance, In case JMS broker is down and I perform a create connection, session etc. or a message send operation within a try block,
control never comes back to catch block or ExceptionListener set for the connection.
My code looks like:
connection = (TopicConnection) (new ActiveMQConnectionFactory(localBrokerURL)).createConnection();
connection.setExceptionListener(new ExceptionListener() {
#Override
public void onException(JMSException arg0) {
System.out.println("Exception Occurred");
}
});
connection.start();
final TopicSession session =conn.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
final Topic sendTopic = session.createTopic("someTopicName");
where Value of localBrokerURL is
failover://(ssl://localhost:61618?trace=true&wireFormat.maxInactivityDuration=0)
Please help. Any hint is highly appreciated.

that is the intent of the failover: transport. It will hide transport failures and automatically try and reconnect, replaying any jms state when a new connection is established.
There is a transportListener that you can use to get transport suspended and resumed events.
If you remove the failover: component from the broker url, you will get all exceptions propagated up to your client.

just set the timeout property on the connection URI and it will throw an error instead of block the thread...
failover://(ssl://localhost:61618?trace=true&wireFormat.maxInactivityDuration=0)?timeout=10000
see http://activemq.apache.org/failover-transport-reference.html

Related

Apache Qpid JMS client message producer getting stuck and not delivering to queue

I am trying to send a message to the Qpid broker over the AMQP 1.0 protocol. The queue is named queue2 and it is already created under default virtualhost. However, producer.send(message) is getting stuck forever. The same code is working for connecting to Azure Service Bus. I'm using qpid-jms-client 0.58. Producer code is:
Hashtable<String, String> hashtable = new Hashtable<>();
hashtable.put("connectionfactory.myFactoryLookup", protocol + "://" + url + "?amqp.idleTimeout=120000&amqp.traceFrames=true");
hashtable.put("queue.myQueueLookup", queueName);
hashtable.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.qpid.jms.jndi.JmsInitialContextFactory");
Context context = new InitialContext(hashtable);
ConnectionFactory factory = (ConnectionFactory) context.lookup("myFactoryLookup");
queue = (Destination) context.lookup("myQueueLookup");
Connection connection = factory.createConnection(username, password);
connection.setExceptionListener(new AmqpConnectionFactory.MyExceptionListener());
connection.start();
Session session=connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// session.createQueue("queue3");
Queue queue = new JmsQueue("queue2");
MessageProducer messageProducer = session.createProducer(queue);
TextMessage textMessage = session.createTextMessage("new message");
messageProducer.send(textMessage)
I can see Connection and session is successfully established on Qpid broker dashboard:
Thread dump for application at time of producing
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x000000078327c550> (a org.apache.qpid.jms.provider.ProgressiveProviderFuture)
at java.lang.Object.wait(Object.java:502)
at org.apache.qpid.jms.provider.ProgressiveProviderFuture.sync(ProgressiveProviderFuture.java:154)
- locked <0x000000078327c550> (a org.apache.qpid.jms.provider.ProgressiveProviderFuture)
at org.apache.qpid.jms.JmsConnection.send(JmsConnection.java:773)
at org.apache.qpid.jms.JmsNoTxTransactionContext.send(JmsNoTxTransactionContext.java:37)
at org.apache.qpid.jms.JmsSession.send(JmsSession.java:964)
at org.apache.qpid.jms.JmsSession.send(JmsSession.java:843)
at org.apache.qpid.jms.JmsMessageProducer.sendMessage(JmsMessageProducer.java:252)
at org.apache.qpid.jms.JmsMessageProducer.send(JmsMessageProducer.java:182)
I have tried to run this example which gave the same result.
In general if the client is not sending it is because the remote has not granted it credit to do so. You can debug the client state using the protocol trace feature (just set PN_TRACE_FRM=true and run the client).
Likely you have misconfigured the Broker-J somehow and the destination you've created doesn't allow any messages to be sent or you've sent enough that you've tripped the write limit. You should consult the configuration guide and review what you've already setup.
Okay Finally got the issue. Filesystem is over 90 per cent full, enforcing flow control. So deleted files from my machine and it started working.
https://qpid.apache.org/releases/qpid-broker-j-7.0.7/book/Java-Broker-Runtime-Disk-Space-Management.html

IBM XMS.Net Listener Hangs Out when connection is closed forbiddenly

Hi I use webpshere mq client 8.0.0.8 and I set my listener at once and start to listen mq,but something went wrong and and myconnection is closed but it throws no error and mylistener hang out and cant listen message.If its throws error I have a mechanism to catch and restart it but that time I failed.Is there any property set to avoid this issue?
I have exceptionlistener and reconnect options in my connectionproperties.But this is not directly work,I have a autoresetevent (receiveCompleteEvent)mechanism,only solution I can find set signal in exceptionlistener,and kill connection.In exception listener I can log connection error notifications but no automatic connection set,
connectionfactory.SetIntProperty(IBM.XMS.XMSC.WMQ_CLIENT_RECONNECT_OPTIONS, IBM.XMS.XMSC.WMQ_CLIENT_RECONNECT);
connectionfactory.SetIntProperty(IBM.XMS.XMSC.WMQ_CLIENT_RECONNECT_TIMEOUT, 150);
private void OnException(Exception ex)
{
QueueStatuslog.Error(String.Format("Unexpected error occured to connection:{0}", ex.ToString()));
try
{
if (receiveCompleteEvent != null)
{
QueueStatuslog.Error(String.Format("Due to connection error send stop signal:{0}", ex.ToString()));
receiveCompleteEvent.Set();
}
Exception, like connection related, will be thrown to application when application makes synchronous MQ API call, like consumer.receive or producer.send. If you are using message listener to receive messages, the message delivery is an asynchronous operation and messages are delivered on the message listener thread. So XMS can not throw exceptions on that thread. Hence it requires another thread, i.e. ExceptionListener to let the application know about any connection related issues.
You will need to setup ExceptionListener on connection and catch any exception thrown. When an exception is thrown, issue Connection.Stop, clean up and reinitialize message receive.
You can also look at using automatic client reconnection and this.

ActiveMQ - handle connection, session, producer and concumer opon failover

I do use failover transport feature by using the following pattern in the broker URL
failover:(tcp://host:port)
Init code goes as follow:
factory = new PooledConnectionFactory(BROKER_URL);
connection = factory.createConnection();
connection.start();
the put message code looks more or less like this:
session = connection.createSession( false, Session.AUTO_ACKNOWLEDGE );
Destination destQueue = new ActiveMQQueue(queue);
MessageProducer producer = session.createProducer(destQueue);
TextMessage msg = session.createTextMessage(message);
producer.send(msg);
When a failover occurs -
[org.apache.activemq.transport.failover.FailoverTransport] Transport (broker) failed, reason: , attempting to automatically reconnect: java.net.SocketException: recv failed: Connection aborted by peer
and got reconnected after
[org.apache.activemq.transport.failover.FailoverTransport] Failed to connect to [broker] after: 10 attempt(s) continuing to retry.
08:55:29,596 INFO [org.apache.activemq.transport.failover.FailoverTransport] Successfully reconnected to broker
do I have to reinitiate a connection? Or to be more specific, do I have to do anything with the connection object to be able to produce/consume message after the failover?
thanks
The whole point of the failover transport is to handle the reconnection for you. The logs you've shown indicate a successful reconnect cycle where the transport has continued to retry to connect to a broker and eventually did so.

Multi Instance MQ set up

I am trying to set up Multi Instance MQ. I have configured NFS and able to see the active and stand by instances using dspmq -x. However my doubt is after this setup how to proceed further.
How can I configure the channel(s). I got CONNAME property should be use for this. e.g. CONNAME(<ip><port>,<ip><port>). I am not aware how to do it exactly.
How many listeners I need to start.
For normal mode of MQ, I follow the below steps:
1. crtmqm QM
2. strmqm QM
3. runmqsc QM
4. runmqlsr -m QM -t tcp -p 1125
5. runmqsc QM
6. define channel(SYSTEM.ADMIN.SVRCONN) chltype(SVRCONN) mcauser('mqm')
For multi-instance MQ, what changes I have to do for the below steps. There are many good documents available for Multi Instance MQ set up, but most of these are limited to how to configure the queue manager with multi-instance. Could anybody please guide me for the remaining steps.
Any guidance is much appreciated.
EDIT
Thanks Shashi and Morag for the guidance.
I have created different listeners on port 1600 in both the servers. I have created the below channel:
DEFINE CHANNEL(MYCHANNEL) CHLTYPE(CLNTCONN) TRPTYPE(TCP)
CONNAME('IP11600),IP2(1600)')
DEFINE CHANNEL(MYCHANNEL) CHLTYPE(SVRCONN) TRPTYPE(TCP) MCAUSER(' ')
Below is the stand alone java code I am using to put a message in queue.
public class MutilInstanceMq
{
public static void main(String[] args)
{
sendMsg("Test Message");
}
public static void sendMsg(String msg)
{
MQQueueConnectionFactory connectionFactory = null;
QueueConnection queueConn = null;
QueueSession queueSession = null;
QueueSender queueSender = null;
TextMessage message = null;
try
{
connectionFactory = new MQQueueConnectionFactory();
connectionFactory.setConnectionNameList("<IP1>(1600), <IP2>(1600)");
connectionFactory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
connectionFactory.setQueueManager("MYQM1");
connectionFactory.setChannel("MYCHANNEL");
queueConn = connectionFactory.createQueueConnection(" ","password");
queueSession = queueConn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
queueSender = queueSession.createSender(queueSession.createQueue("MYQ"));
queueSender.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
message = queueSession.createTextMessage(msg);
message.setJMSCorrelationID("12345");
queueSender.send(message);
queueConn.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
With the above code I end up with the below exception while creating the connection.
> com.ibm.msg.client.jms.DetailedJMSException: JMSWMQ0018: Failed to
> connect to queue manager 'MYQM1' with connection mode 'Client' and
> host name 'IP1(1600),IP2(1600)'. Check the queue manager is
> started and if running in client mode, check there is a listener
> running. Please see the linked exception for more information.
Detailed Print stack trace is:
com.ibm.msg.client.jms.DetailedJMSException: JMSWMQ0018: Failed to connect to queue manager 'MYQM1' with connection mode 'Client' and host name 'IP1(1600),IP2(1600)'. Check the queue manager is started and if running in client mode, check there is a listener running. Please see the linked exception for more information.
at com.ibm.msg.client.wmq.common.internal.Reason.reasonToException(Reason.java:608)
at com.ibm.msg.client.wmq.common.internal.Reason.createException(Reason.java:236)
at com.ibm.msg.client.wmq.internal.WMQConnection.<init>(WMQConnection.java:440)
at com.ibm.msg.client.wmq.factories.WMQConnectionFactory.createV7ProviderConnection(WMQConnectionFactory.java:7062)
at com.ibm.msg.client.wmq.factories.WMQConnectionFactory.createProviderConnection(WMQConnectionFactory.java:6453)
at com.ibm.msg.client.jms.admin.JmsConnectionFactoryImpl.createConnection(JmsConnectionFactoryImpl.java:295)
at com.ibm.mq.jms.MQConnectionFactory.createCommonConnection(MQConnectionFactory.java:6230)
at com.ibm.mq.jms.MQQueueConnectionFactory.createQueueConnection(MQQueueConnectionFactory.java:144)
at MutilInstanceMq.sendMsg(MutilInstanceMq.java:40)
at MutilInstanceMq.main(MutilInstanceMq.java:17)
Caused by: com.ibm.mq.MQException: JMSCMQ0001: WebSphere MQ call failed with compcode '2' ('MQCC_FAILED') reason '2543' ('MQRC_STANDBY_Q_MGR').
at com.ibm.msg.client.wmq.common.internal.Reason.createException(Reason.java:223)
... 8 more
Caused by: com.ibm.mq.jmqi.JmqiException: CC=2;RC=2543;AMQ9204: Connection to host 'IP2(1600)' rejected. [1=com.ibm.mq.jmqi.JmqiException[CC=2;RC=2543;AMQ9487: Remote queue manager is a standby queue manager instance. [3=MYCHANNEL]],3=IP2(1600),5=RemoteConnection.analyseErrorSegment]
at com.ibm.mq.jmqi.remote.internal.RemoteFAP.jmqiConnect(RemoteFAP.java:2010)
at com.ibm.mq.jmqi.remote.internal.RemoteFAP.jmqiConnect(RemoteFAP.java:1227)
at com.ibm.msg.client.wmq.internal.WMQConnection.<init>(WMQConnection.java:355)
... 7 more
Caused by: com.ibm.mq.jmqi.JmqiException: CC=2;RC=2059;AMQ9204: Connection to host 'IP1(1600)' rejected. [3=IP1(1600)]
at com.ibm.mq.jmqi.remote.internal.RemoteFAP.jmqiConnect(RemoteFAP.java:1980)
... 9 more
Where I am going wrong? Meanwhile I have turned off channel authentication and able to connect to the queue.
To answer your explicit questions:
If you want to use the comma-separated CONNAME method, then you'll end up with something like this. CONNAME('machine1(1234),machine2(1234)'). You should have the same port number in both.
You have two options here. Either use runmqlsr on each machine - so you have two listeners, on the same port. The purpose of the one on the primary machine is for connections to be able to connect to the queue manager. The purpose of the one on the standby machine is to reject connections which try to connect there more quickly than they could be rejected by TCP working out that there is no listener. It also means that the error reported by the connection for the reason it could not connect is much more explicit - "This machine is the standby" rather than "no TCP listener here".
The alternate option is to define a LISTENER object and have it controlled by the queue manager, this way it will only run where the queue manager runs. This keeps the configuration all within the queue manager, but does mean you don't get the benefits outlined above.
The steps are well documented in Knowledge Center here: http://www-01.ibm.com/support/knowledgecenter/SSFKSJ_7.1.0/com.ibm.mq.doc/fa70161_.htm?lang=en. How to verify the multi-instance setup is described here: http://www-01.ibm.com/support/knowledgecenter/SSFKSJ_7.1.0/com.ibm.mq.doc/fa70163_.htm?lang=en.

Reconnecting with MQ - issues

I'm looking forward to implement a somewhat intelligent MQ comms module, which should be tolerant for the outages in the network connection. Basically it should try to reconnect each 5 seconds if connection was lost.
The problem is the following. I use the following code for reading:
queueMessage = new MQMessage();
queueMessage.Format = MQC.MQFMT_STRING;
queueGetMessageOptions = new MQGetMessageOptions();
queueGetMessageOptions.Options = MQC.MQGMO_SYNCPOINT + MQC.MQGMO_WAIT + MQC.MQGMO_FAIL_IF_QUIESCING;
queueGetMessageOptions.WaitInterval = 50;
producerQueue.Get(queueMessage, queueGetMessageOptions);
msg = queueMessage.ReadBytes(queueMessage.MessageLength);
(Of course I successfully connect to the queuemanager before etc.)
I got the following issue: when this routine runs, but at the time of .Get there's no connection, the code simply hangs and stays in the .Get.
I use a timer to see if there's a timeout (in theory even that shouldn't be necessary, is that right?) and at the timeout I try to reconnect. BUT when this timeout expires, I still see that the queuemanager reports that it's connected, while its clearly not (no physical connection is present anymore). This issue has popped up since I use SYNCPOINT, and I experience the same when I cut connection during writing, or in this case I try to force a Disconnect on the queuemanager. So please help, what settings shall I use to avoid getting stuck in Get and Put and rather have an MQException thrown or something controllable?
Thanks!
UPDATE: I used the following code to connect to the QueueManager.
Hashtable props = new Hashtable();
props.Add(MQC.HOST_NAME_PROPERTY, Host);
props.Add(MQC.PORT_PROPERTY, Port);
props.Add(MQC.CHANNEL_PROPERTY, ChannelInfo);
if(User!="") props.Add(MQC.USER_ID_PROPERTY, User);
if(Password!="") props.Add(MQC.PASSWORD_PROPERTY, Password);
props.Add(MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES_MANAGED);
queueManager = new MQQueueManager(QueueManagerName, props);
producerQueue = queueManager.AccessQueue(
ProducerQueueName,
MQC.MQOO_INPUT_AS_Q_DEF // open queue for input
+ MQC.MQOO_FAIL_IF_QUIESCING); // but not if MQM stopping
consumerQueue = queueManager.AccessQueue(
ConsumerQueueName,
MQC.MQOO_OUTPUT + MQC.MQOO_BROWSE + MQC.MQOO_INPUT_AS_Q_DEF // open queue for output
+ MQC.MQOO_FAIL_IF_QUIESCING); // but not if MQM stopping
Needless to say that normally the code works well. Read/Write, connect/disconnect works as it should, I only have to figure out the current issue.
Thanks!
What version of MQ are you using? For automatic reconnection to work the queue manager need to be at least at MQ v701 and MQ .NET client needs to be a MQ v7.1 level.
Assuming you are using MQ v7.1 .NET client, you need to specify reconnect option during connection create. You will need to enable reconnection by adding something like:
props.Add(MQC.CONNECT_OPTIONS_PROPERTY, MQC.MQCNO_RECONNECT);
Reconnection can be enabled/disabled from mqclient.ini file also.
But what is surprising is why the Get/Put are hanging when there is no network connection. Hope you are not connecting a queue manager running on the same machine as your application. There is no need to set any timer or something like that. You can issue MQ calls and if there is anything wrong with connection, an exception will be thrown.
Update:
I think you are referring to IsConnected property of MQQueueManager class. The documentation says the value of this property: "If true, a connection to the queue manager has been made, and is not known to be broken. Any calls to IsConnected do not actively attempt to reach the queue manager, so it is possible that physical connectivity can break, but IsConnected can still return true. The IsConnected state is only updated when activity, for example, putting a message, getting a message, is performed on the queue manager.
If false, a connection to the queue manager has not been made, or has been broken, or has been disconnected."
As you can see a True value does not mean the connection is still ON. My suggestion would be to call a method, Put/Get and handle any exception thrown.
Put/Get/Disconnect calls hanging appears to be a problem. My suggestion would be raise a PMR with IBM.

Resources