Ibm mq 在使用自动重新连接的IBM MQ客户端应用程序中检测重新连接

Ibm mq 在使用自动重新连接的IBM MQ客户端应用程序中检测重新连接,ibm-mq,Ibm Mq,我正在使用配置了自动重新连接的IBM MQ JMS类(IBM MQ版本8.0.0.4)。根据文档,重新连接是隐式发生的。我想在重新连接的情况下发出一个简单的日志语句。因此,当这种情况发生时,我需要以某种方式得到通知 在第页的IBM文档中,我无意中看到了“检测故障转移”一节,其中说: 重新连接感知:向注册MQCBT\u事件处理程序事件处理程序 队列管理器。事件处理程序在MQRC_重新连接时发布 当客户端开始尝试重新连接到服务器时 成功重新连接后,MQRC_重新连接。然后,您可以运行 用于重新建立可

我正在使用配置了自动重新连接的IBM MQ JMS类(IBM MQ版本8.0.0.4)。根据文档,重新连接是隐式发生的。我想在重新连接的情况下发出一个简单的日志语句。因此,当这种情况发生时,我需要以某种方式得到通知

在第页的IBM文档中,我无意中看到了“检测故障转移”一节,其中说:

重新连接感知:向注册MQCBT\u事件处理程序事件处理程序 队列管理器。事件处理程序在MQRC_重新连接时发布 当客户端开始尝试重新连接到服务器时 成功重新连接后,MQRC_重新连接。然后,您可以运行 用于重新建立可预测状态的例程,以便客户端 应用程序可以继续处理

不幸的是,我没有找到Java/JMS的代码示例来演示如何以及在何处注册这样的事件处理程序。我不知道这在我的情况下是否得到支持。谁能给我提供正确的方向,甚至提供一个代码示例?多谢各位

2020年2月5日起的问题更新:

在从2020年1月27日收到Sashi的初始答案后,添加了我自己创建的以下代码示例

public static void main(String[] args) {
    Connection connection = null;
    Session session = null;
    Object destination = null;
    MessageProducer producer = null;

    try {
        JmsFactoryFactory jmsFactoryFactory = JmsFactoryFactory.getInstance(WMQConstants.WMQ_PROVIDER);
        JmsConnectionFactory cf = jmsFactoryFactory.createConnectionFactory();

        cf.setStringProperty(WMQConstants.WMQ_HOST_NAME, HOST);
        cf.setIntProperty(WMQConstants.WMQ_PORT, PORT);
        cf.setStringProperty(WMQConstants.WMQ_CHANNEL, CHANNEL);
        cf.setIntProperty(WMQConstants.WMQ_CONNECTION_MODE, WMQConstants.WMQ_CM_CLIENT);
        cf.setStringProperty(WMQConstants.WMQ_QUEUE_MANAGER, QM_NAME);
        cf.setIntProperty(WMQConstants.WMQ_CLIENT_RECONNECT_OPTIONS, WMQConstants.WMQ_CLIENT_RECONNECT);
        cf.setIntProperty(WMQConstants.WMQ_CLIENT_RECONNECT_TIMEOUT, RECONNECT_TIMEOUT);

        connection = cf.createConnection();
        connection.setExceptionListener(new MQExceptionListener());
        session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        destination = session.createQueue(QUEUE);
        producer = session.createProducer((Destination)destination);
        connection.start();
    } catch (JMSException ex) {
        LOGGER.error(ex.toString());
    }
}

public class MQExceptionListener implements ExceptionListener {
    public void onException(JMSException e) {
        System.out.println(e);
        if(e.getLinkedException() != null)
            System.out.println(e.getLinkedException());
    }
}
这是我在日志中得到的:

ERROR [Main.main:57] (main) com.ibm.msg.client.jms.DetailedIllegalStateException: JMSWMQ0018: Failed to connect to queue manager '<hostname>' with connection mode 'Client' and host name '<hostname>(<port>)'.
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.
ERROR [Main.main:61] (main) Inner exceptions:
ERROR [Main.main:65] (main) com.ibm.mq.MQException: JMSCMQ0001: IBM MQ call failed with compcode '2' ('MQCC_FAILED') reason '2538' ('MQRC_HOST_NOT_AVAILABLE').
ERROR [Main.main:65] (main) com.ibm.mq.jmqi.JmqiException: CC=2;RC=2538;AMQ9204: Connection to host '<hostname>(<port>)' rejected. [1=com.ibm.mq.jmqi.JmqiException[CC=2;RC=2538;AMQ9204: Connection to host '<hostname>/<ip>:<port>' rejected. [1=java.net.ConnectException[Connection refused: connect],3=<hostname>/<ip>:<port>,4=TCP,5=Socket.connect]],3=<hostname>(<port>),5=RemoteTCPConnection.bindAndConnectSocket]
ERROR [Main.main:65] (main) com.ibm.mq.jmqi.JmqiException: CC=2;RC=2538;AMQ9204: Connection to host '<hostname>/<ip>:<port>' rejected. [1=java.net.ConnectException[Connection refused: connect],3=<hostname>/<ip>:<port>,4=TCP,5=Socket.connect]
ERROR [Main.main:65] (main) java.net.ConnectException: Connection refused: connect
MQConnectionDetails.java

MQWriter.java

MQExceptionListener.java

我运行的测试场景如下所示:

  • 确保IBM MQ在TCP端口1414(在Amazon EC2上运行的IBM MQ Docker容器)上可用
  • 运行上面的应用程序(application.java),确保它向队列发送消息
  • 通过将端口从1414更改为1415,更改Amazon EC2安全组上的防火墙配置,从而使客户端无法使用IBM MQ
  • 这是我观察到的:

    • 只有在90秒不活动之后,客户端才开始抛出异常。我不明白,因为我的重新连接超时被设置为60秒,所以这里有30秒
    • MQExceptionListener仅被调用一次(第一次)
    • 没有原因代码2544(MQRC_重新连接),只有2009(MQRC_连接_断开)存在。为什么呢
    以下是引发的异常的摘要:

    控制台上的异常:

    2020年2月12日起的问题更新

    根据JoshMc 2020年2月11日的回答添加了此样本和调查结果。我对这个样本的评论如下:

    • 我现在使用MQ*类,并按照建议设置重新连接选项
    • 然而,重新连接仍然没有发生
    MQWriter2.java

    控制台输出

    2020-02-12 08:39:11628信息[MQWriter2:29](main)正在初始化连接以写入54.161.121.207:1414上的队列DEV.queue.1。。。
    2020-02-12 08:39:14552信息[应用程序运行:19](主)正在向MQ服务器发送消息Hello Testing 1。。。
    2020-02-12 08:39:15710信息[应用程序运行:19](主)正在向MQ服务器发送消息Hello Testing 2。。。
    2020-02-12 08:39:16841信息[应用程序运行:19](主)正在向MQ服务器发送消息Hello Testing 3。。。
    ...
    2020-02-12 08:39:41973信息[应用程序运行:19](主)正在向MQ服务器发送消息Hello Testing 25。。。
    2020-02-12 08:41:27314错误[MQExceptionListener.OneException:14](JMSCCThreadPoolWorker-10)=====
    2020-02-12 08:41:27314错误[MQExceptionListener.OneException:15](JMSCCThreadPoolWorker-10)com.ibm.msg.client.jms.DetailedJMSExException:JMSWMQ1107:此连接出现问题。
    IBM MQ JMS连接发生错误。
    使用链接异常确定此错误的原因。
    2020-02-12 08:41:27314错误[MQWriter2.write:49](主)将消息发送到写入队列时出错
    com.ibm.msg.client.jms.DetailedJMSExException:JMSWMQ2007:未能将消息发送到目标“DEV.QUEUE.1”。
    JMS试图执行MQPUT或MQPUT1;但是,IBM MQ报告了一个错误。
    使用链接异常确定此错误的原因。
    位于com.ibm.msg.client.wmq.common.internal.Reason.reasonToException(Reason.java:595)
    位于com.ibm.msg.client.wmq.common.internal.Reason.createException(Reason.java:215)
    位于com.ibm.msg.client.wmq.internal.WMQMessageProducer.checkJmqiCallSuccess(WMQMessageProducer.java:1288)
    位于com.ibm.msg.client.wmq.internal.WMQMessageProducer.checkJmqiCallSuccess(WMQMessageProducer.java:1245)
    在com.ibm.msg.client.wmq.internal.WMQMessageProducer.access$800(WMQMessageProducer.java:76)
    位于com.ibm.msg.client.wmq.internal.WMQMessageProducer$SpiIdentifiedProducerShadow.sendInternal(WMQMessageProducer.java:906)
    位于com.ibm.msg.client.wmq.internal.WMQMessageProducer$ProducerShadow.send(WMQMessageProducer.java:566)
    位于com.ibm.msg.client.wmq.internal.WMQMessageProducer.send(WMQMessageProducer.java:1428)
    在com.ibm.msg.client.jms.internal.JmsMessageProducerImpl.sendMessage上(JmsMessageProducerImpl.java:855)
    位于com.ibm.msg.client.jms.internal.JmsMessageProducerImpl.synchronousSendInternal(JmsMessageProducerImpl.java:2055)
    位于com.ibm.msg.client.jms.internal.JmsMessageProducerImpl.sendInternal(JmsMessageProducerImpl.java:1993)
    位于com.ibm.msg.client.jms.internal.JmsMessageProducerImpl.send(JmsMessageProducerImpl.java:1486)
    位于com.ibm.mq.jms.MQMessageProducer.send(MQMessageProducer.java:293)
    位于org.example.MQWriter2.write(MQWriter2.java:47)
    位于org.example.Application.run(Application.java:20)
    位于org.example.Application.main(Application.java:11)
    原因:com.ibm.mq.MQException:JMSCMQ0001:ibm mq调用失败,代码为“2”(“MQCC_失败”)原因为“2009”(“MQRC_连接中断”)。
    位于com.ibm.msg.client.wmq.common.internal.Reason.createException(Reason.java:203)
    ... 14多
    原因:com.ibm.mq.jmqi.jmqi异常:CC=2;RC=2009
    位于com.ibm.mq.jmqi.remote.api.RemoteHconn$ReconnectionState.recordFailure(RemoteHconn.java:4931)
    位于com.ibm.mq.jmqi.remote.api.RemoteHco
    
    public class Application {
        private static final Logger LOGGER = LoggerFactory.getLogger(Application.class);
    
        public static void main(String[] args) {
            new Application().run();
        }
    
        private void run() {
            MQWriter writer = new MQWriter();
            int i = 1;
            while (true) {
                String message = "Hello Testing " + i;
                LOGGER.info("Sending message {} to MQ server...", message);
                writer.write(message);
                i++;
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    public class MQConnectionDetails {
        public static final String HOST = "XXX.XXX.XXX.XXX";
        public static final int PORT = 1414;
        public static final String QM_NAME = "QM1";
        public static final String CHANNEL = "DEV.APP.SVRCONN";
        public static final String QUEUE = "DEV.QUEUE.1";
        public static final int RECONNECT_TIMEOUT = 60; // 1 minute
    }
    
    public class MQWriter {
    
        private static final Logger LOGGER = LoggerFactory.getLogger(MQWriter.class);
    
        private Connection connection = null;
        private Session session = null;
        private Object destination = null;
        private MessageProducer producer = null;
    
        public MQWriter() {
            try {
                JmsFactoryFactory jff = JmsFactoryFactory.getInstance(WMQConstants.WMQ_PROVIDER);
                JmsConnectionFactory jcf = jff.createConnectionFactory();
                jcf.setStringProperty(WMQConstants.WMQ_HOST_NAME, MQConnectionDetails.HOST);
                jcf.setIntProperty(WMQConstants.WMQ_PORT, MQConnectionDetails.PORT);
                jcf.setStringProperty(WMQConstants.WMQ_CHANNEL, MQConnectionDetails.CHANNEL);
                jcf.setIntProperty(WMQConstants.WMQ_CONNECTION_MODE, WMQConstants.WMQ_CM_CLIENT);
                jcf.setStringProperty(WMQConstants.WMQ_QUEUE_MANAGER, MQConnectionDetails.QM_NAME);
                jcf.setIntProperty(WMQConstants.WMQ_CLIENT_RECONNECT_OPTIONS, WMQConstants.WMQ_CLIENT_RECONNECT);
                jcf.setIntProperty(WMQConstants.WMQ_CLIENT_RECONNECT_TIMEOUT, MQConnectionDetails.RECONNECT_TIMEOUT);
    
                LOGGER.info("Initializing connection to write queue {} on {}:{}...",
                        MQConnectionDetails.QUEUE,
                        MQConnectionDetails.HOST,
                        MQConnectionDetails.PORT);
                connection = jcf.createConnection();
                connection.setExceptionListener(new MQExceptionListener());
                session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
                destination = session.createQueue(MQConnectionDetails.QUEUE);
                producer = session.createProducer((Destination)destination);
                connection.start();
            } catch (JMSException ex) {
                LOGGER.error("Error initializing connection to write queue", ex);
            }
        }
    
        public void write(String message) {
            try {
                TextMessage textMessage = session.createTextMessage(message);
                producer.send(textMessage);
            } catch (Exception ex) {
                LOGGER.error("Error sending message to write queue", ex);
            }
        }
    }
    
    public class MQExceptionListener implements ExceptionListener {
        private static final Logger LOGGER = LoggerFactory.getLogger(MQExceptionListener.class);
    
        public void onException(JMSException ex) {
            LOGGER.error("=====");
            LOGGER.error(ex.toString());
            if (ex.getLinkedException() != null) {
                LOGGER.error(ex.getLinkedException().toString());
            }
            LOGGER.error("=====");
        }
    }
    
    2020-02-11 09:50:16,155 INFO [Application.run:21] (main) Sending message Hello Testing 13 to MQ server...
    2020-02-11 09:50:17,285 INFO [Application.run:21] (main) Sending message Hello Testing 14 to MQ server...
    2020-02-11 09:50:18,413 INFO [Application.run:21] (main) Sending message Hello Testing 15 to MQ server...
    2020-02-11 09:50:19,555 INFO [Application.run:21] (main) Sending message Hello Testing 16 to MQ server...
    2020-02-11 09:51:45,966 ERROR [MQExceptionListener.onException:14] (JMSCCThreadPoolWorker-6) =====
    2020-02-11 09:51:45,966 ERROR [MQExceptionListener.onException:15] (JMSCCThreadPoolWorker-6) com.ibm.msg.client.jms.DetailedJMSException: JMSWMQ1107: A problem with this connection has occurred.
    An error has occurred with the IBM MQ JMS connection.
    Use the linked exception to determine the cause of this error.
    2020-02-11 09:51:45,966 ERROR [MQExceptionListener.onException:17] (JMSCCThreadPoolWorker-6) com.ibm.mq.MQException: MQ delivered an asynchronous event with completion code '2', and reason '2009'.
    2020-02-11 09:51:45,966 ERROR [MQExceptionListener.onException:19] (JMSCCThreadPoolWorker-6) =====
    2020-02-11 09:51:45,967 ERROR [MQWriter.write:52] (main) Error sending message to write queue
    com.ibm.msg.client.jms.DetailedJMSException: JMSWMQ2007: Failed to send a message to destination 'DEV.QUEUE.1'.
    JMS attempted to perform an MQPUT or MQPUT1; however IBM MQ reported an error.
    Use the linked exception to determine the cause of this error.
        at com.ibm.msg.client.wmq.common.internal.Reason.reasonToException(Reason.java:595)
        at com.ibm.msg.client.wmq.common.internal.Reason.createException(Reason.java:215)
        at com.ibm.msg.client.wmq.internal.WMQMessageProducer.checkJmqiCallSuccess(WMQMessageProducer.java:1288)
        at com.ibm.msg.client.wmq.internal.WMQMessageProducer.checkJmqiCallSuccess(WMQMessageProducer.java:1245)
        at com.ibm.msg.client.wmq.internal.WMQMessageProducer.access$800(WMQMessageProducer.java:76)
        at com.ibm.msg.client.wmq.internal.WMQMessageProducer$SpiIdentifiedProducerShadow.sendInternal(WMQMessageProducer.java:906)
        at com.ibm.msg.client.wmq.internal.WMQMessageProducer$ProducerShadow.send(WMQMessageProducer.java:566)
        at com.ibm.msg.client.wmq.internal.WMQMessageProducer.send(WMQMessageProducer.java:1428)
        at com.ibm.msg.client.jms.internal.JmsMessageProducerImpl.sendMessage(JmsMessageProducerImpl.java:855)
        at com.ibm.msg.client.jms.internal.JmsMessageProducerImpl.synchronousSendInternal(JmsMessageProducerImpl.java:2055)
        at com.ibm.msg.client.jms.internal.JmsMessageProducerImpl.sendInternal(JmsMessageProducerImpl.java:1993)
        at com.ibm.msg.client.jms.internal.JmsMessageProducerImpl.send(JmsMessageProducerImpl.java:1486)
        at com.ibm.mq.jms.MQMessageProducer.send(MQMessageProducer.java:293)
        at org.example.MQWriter.write(MQWriter.java:50)
        at org.example.Application.run(Application.java:22)
        at org.example.Application.main(Application.java:13)
    Caused by: com.ibm.mq.MQException: JMSCMQ0001: IBM MQ call failed with compcode '2' ('MQCC_FAILED') reason '2009' ('MQRC_CONNECTION_BROKEN').
        at com.ibm.msg.client.wmq.common.internal.Reason.createException(Reason.java:203)
        ... 14 more
    Caused by: com.ibm.mq.jmqi.JmqiException: CC=2;RC=2009
        at com.ibm.mq.jmqi.remote.api.RemoteHconn$ReconnectionState.recordFailure(RemoteHconn.java:4931)
        at com.ibm.mq.jmqi.remote.api.RemoteHconn.setReconnectionFailureInner(RemoteHconn.java:2650)
        at com.ibm.mq.jmqi.remote.api.RemoteParentHconn.setReconnectionFailure(RemoteParentHconn.java:152)
        at com.ibm.mq.jmqi.remote.impl.RemoteReconnectThread.bestHconn(RemoteReconnectThread.java:265)
        at com.ibm.mq.jmqi.remote.impl.RemoteReconnectThread.run(RemoteReconnectThread.java:115)
        at com.ibm.msg.client.commonservices.workqueue.WorkQueueItem.runTask(WorkQueueItem.java:319)
        at com.ibm.msg.client.commonservices.workqueue.SimpleWorkQueueItem.runItem(SimpleWorkQueueItem.java:99)
        at com.ibm.msg.client.commonservices.workqueue.WorkQueueItem.run(WorkQueueItem.java:343)
        at com.ibm.msg.client.commonservices.workqueue.WorkQueueManager.runWorkQueueItem(WorkQueueManager.java:312)
        at com.ibm.msg.client.commonservices.j2se.workqueue.WorkQueueManagerImplementation$ThreadPoolWorker.run(WorkQueueManagerImplementation.java:1227)
    2020-02-11 09:51:46,969 INFO [Application.run:21] (main) Sending message Hello Testing 17 to MQ server...
    2020-02-11 09:51:46,972 ERROR [MQWriter.write:52] (main) Error sending message to write queue
    com.ibm.msg.client.jms.DetailedJMSException: JMSWMQ2007: Failed to send a message to destination 'DEV.QUEUE.1'.
    JMS attempted to perform an MQPUT or MQPUT1; however IBM MQ reported an error.
    Use the linked exception to determine the cause of this error.
        at com.ibm.msg.client.wmq.common.internal.Reason.reasonToException(Reason.java:595)
        at com.ibm.msg.client.wmq.common.internal.Reason.createException(Reason.java:215)
        at com.ibm.msg.client.wmq.internal.WMQMessageProducer.checkJmqiCallSuccess(WMQMessageProducer.java:1288)
        at com.ibm.msg.client.wmq.internal.WMQMessageProducer.checkJmqiCallSuccess(WMQMessageProducer.java:1245)
        at com.ibm.msg.client.wmq.internal.WMQMessageProducer.access$800(WMQMessageProducer.java:76)
        at com.ibm.msg.client.wmq.internal.WMQMessageProducer$SpiIdentifiedProducerShadow.sendInternal(WMQMessageProducer.java:906)
        at com.ibm.msg.client.wmq.internal.WMQMessageProducer$ProducerShadow.send(WMQMessageProducer.java:566)
        at com.ibm.msg.client.wmq.internal.WMQMessageProducer.send(WMQMessageProducer.java:1428)
        at com.ibm.msg.client.jms.internal.JmsMessageProducerImpl.sendMessage(JmsMessageProducerImpl.java:855)
        at com.ibm.msg.client.jms.internal.JmsMessageProducerImpl.synchronousSendInternal(JmsMessageProducerImpl.java:2055)
        at com.ibm.msg.client.jms.internal.JmsMessageProducerImpl.sendInternal(JmsMessageProducerImpl.java:1993)
        at com.ibm.msg.client.jms.internal.JmsMessageProducerImpl.send(JmsMessageProducerImpl.java:1486)
        at com.ibm.mq.jms.MQMessageProducer.send(MQMessageProducer.java:293)
        at org.example.MQWriter.write(MQWriter.java:50)
        at org.example.Application.run(Application.java:22)
        at org.example.Application.main(Application.java:13)
    Caused by: com.ibm.mq.MQException: JMSCMQ0001: IBM MQ call failed with compcode '2' ('MQCC_FAILED') reason '2009' ('MQRC_CONNECTION_BROKEN').
        at com.ibm.msg.client.wmq.common.internal.Reason.createException(Reason.java:203)
        ... 14 more
    Caused by: com.ibm.mq.jmqi.JmqiException: CC=2;RC=2009
        at com.ibm.mq.jmqi.remote.api.RemoteHconn$ReconnectionState.recordFailure(RemoteHconn.java:4931)
        at com.ibm.mq.jmqi.remote.api.RemoteHconn.setReconnectionFailureInner(RemoteHconn.java:2650)
        at com.ibm.mq.jmqi.remote.api.RemoteParentHconn.setReconnectionFailure(RemoteParentHconn.java:152)
        at com.ibm.mq.jmqi.remote.impl.RemoteReconnectThread.bestHconn(RemoteReconnectThread.java:265)
        at com.ibm.mq.jmqi.remote.impl.RemoteReconnectThread.run(RemoteReconnectThread.java:115)
        at com.ibm.msg.client.commonservices.workqueue.WorkQueueItem.runTask(WorkQueueItem.java:319)
        at com.ibm.msg.client.commonservices.workqueue.SimpleWorkQueueItem.runItem(SimpleWorkQueueItem.java:99)
        at com.ibm.msg.client.commonservices.workqueue.WorkQueueItem.run(WorkQueueItem.java:343)
        at com.ibm.msg.client.commonservices.workqueue.WorkQueueManager.runWorkQueueItem(WorkQueueManager.java:312)
        at com.ibm.msg.client.commonservices.j2se.workqueue.WorkQueueManagerImplementation$ThreadPoolWorker.run(WorkQueueManagerImplementation.java:1227)
    
    public class MQWriter2 {
    
        private static final Logger LOGGER = LoggerFactory.getLogger(MQWriter2.class);
    
        private Connection connection = null;
        private Session session = null;
        private Queue destination = null;
        private MessageProducer producer = null;
    
        public MQWriter2() {
            try {
                MQConnectionFactory factory = new MQConnectionFactory();
                factory.setTransportType(WMQConstants.WMQ_CM_CLIENT);
                factory.setConnectionNameList("XXX.XXX.XXX.XXX(1414)");
                factory.setQueueManager(MQConnectionDetails.QM_NAME);
                factory.setChannel(MQConnectionDetails.CHANNEL);
                factory.setClientReconnectOptions(WMQConstants.WMQ_CLIENT_RECONNECT);
                factory.setClientReconnectTimeout(MQConnectionDetails.RECONNECT_TIMEOUT);
    
                LOGGER.info("Initializing connection to write queue {} on {}:{}...",
                        MQConnectionDetails.QUEUE,
                        MQConnectionDetails.HOST,
                        MQConnectionDetails.PORT);
                connection = factory.createConnection();
                connection.setExceptionListener(new MQExceptionListener());
                session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
                destination = session.createQueue(MQConnectionDetails.QUEUE);
                producer = session.createProducer(destination);
                connection.start();
            } catch (JMSException ex) {
                LOGGER.error("Error initializing connection to write queue", ex);
            }
        }
    
        public void write(String message) {
            try {
                TextMessage textMessage = session.createTextMessage(message);
                producer.send(textMessage);
            } catch (Exception ex) {
                LOGGER.error("Error sending message to write queue", ex);
            }
        }
    }
    
    2020-02-12 08:39:11,628 INFO [MQWriter2.<init>:29] (main) Initializing connection to write queue DEV.QUEUE.1 on 54.161.121.207:1414...
    2020-02-12 08:39:14,552 INFO [Application.run:19] (main) Sending message Hello Testing 1 to MQ server...
    2020-02-12 08:39:15,710 INFO [Application.run:19] (main) Sending message Hello Testing 2 to MQ server...
    2020-02-12 08:39:16,841 INFO [Application.run:19] (main) Sending message Hello Testing 3 to MQ server...
    ...
    2020-02-12 08:39:41,973 INFO [Application.run:19] (main) Sending message Hello Testing 25 to MQ server...
    2020-02-12 08:41:27,314 ERROR [MQExceptionListener.onException:14] (JMSCCThreadPoolWorker-10) =====
    2020-02-12 08:41:27,314 ERROR [MQExceptionListener.onException:15] (JMSCCThreadPoolWorker-10) com.ibm.msg.client.jms.DetailedJMSException: JMSWMQ1107: A problem with this connection has occurred.
    An error has occurred with the IBM MQ JMS connection.
    Use the linked exception to determine the cause of this error.
    2020-02-12 08:41:27,314 ERROR [MQWriter2.write:49] (main) Error sending message to write queue
    com.ibm.msg.client.jms.DetailedJMSException: JMSWMQ2007: Failed to send a message to destination 'DEV.QUEUE.1'.
    JMS attempted to perform an MQPUT or MQPUT1; however IBM MQ reported an error.
    Use the linked exception to determine the cause of this error.
        at com.ibm.msg.client.wmq.common.internal.Reason.reasonToException(Reason.java:595)
        at com.ibm.msg.client.wmq.common.internal.Reason.createException(Reason.java:215)
        at com.ibm.msg.client.wmq.internal.WMQMessageProducer.checkJmqiCallSuccess(WMQMessageProducer.java:1288)
        at com.ibm.msg.client.wmq.internal.WMQMessageProducer.checkJmqiCallSuccess(WMQMessageProducer.java:1245)
        at com.ibm.msg.client.wmq.internal.WMQMessageProducer.access$800(WMQMessageProducer.java:76)
        at com.ibm.msg.client.wmq.internal.WMQMessageProducer$SpiIdentifiedProducerShadow.sendInternal(WMQMessageProducer.java:906)
        at com.ibm.msg.client.wmq.internal.WMQMessageProducer$ProducerShadow.send(WMQMessageProducer.java:566)
        at com.ibm.msg.client.wmq.internal.WMQMessageProducer.send(WMQMessageProducer.java:1428)
        at com.ibm.msg.client.jms.internal.JmsMessageProducerImpl.sendMessage(JmsMessageProducerImpl.java:855)
        at com.ibm.msg.client.jms.internal.JmsMessageProducerImpl.synchronousSendInternal(JmsMessageProducerImpl.java:2055)
        at com.ibm.msg.client.jms.internal.JmsMessageProducerImpl.sendInternal(JmsMessageProducerImpl.java:1993)
        at com.ibm.msg.client.jms.internal.JmsMessageProducerImpl.send(JmsMessageProducerImpl.java:1486)
        at com.ibm.mq.jms.MQMessageProducer.send(MQMessageProducer.java:293)
        at org.example.MQWriter2.write(MQWriter2.java:47)
        at org.example.Application.run(Application.java:20)
        at org.example.Application.main(Application.java:11)
    Caused by: com.ibm.mq.MQException: JMSCMQ0001: IBM MQ call failed with compcode '2' ('MQCC_FAILED') reason '2009' ('MQRC_CONNECTION_BROKEN').
        at com.ibm.msg.client.wmq.common.internal.Reason.createException(Reason.java:203)
        ... 14 more
    Caused by: com.ibm.mq.jmqi.JmqiException: CC=2;RC=2009
        at com.ibm.mq.jmqi.remote.api.RemoteHconn$ReconnectionState.recordFailure(RemoteHconn.java:4931)
        at com.ibm.mq.jmqi.remote.api.RemoteHconn.setReconnectionFailureInner(RemoteHconn.java:2650)
        at com.ibm.mq.jmqi.remote.api.RemoteParentHconn.setReconnectionFailure(RemoteParentHconn.java:152)
        at com.ibm.mq.jmqi.remote.impl.RemoteReconnectThread.bestHconn(RemoteReconnectThread.java:265)
        at com.ibm.mq.jmqi.remote.impl.RemoteReconnectThread.run(RemoteReconnectThread.java:115)
        at com.ibm.msg.client.commonservices.workqueue.WorkQueueItem.runTask(WorkQueueItem.java:319)
        at com.ibm.msg.client.commonservices.workqueue.SimpleWorkQueueItem.runItem(SimpleWorkQueueItem.java:99)
        at com.ibm.msg.client.commonservices.workqueue.WorkQueueItem.run(WorkQueueItem.java:343)
        at com.ibm.msg.client.commonservices.workqueue.WorkQueueManager.runWorkQueueItem(WorkQueueManager.java:312)
        at com.ibm.msg.client.commonservices.j2se.workqueue.WorkQueueManagerImplementation$ThreadPoolWorker.run(WorkQueueManagerImplementation.java:1227)
    
        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);
    
    jcf.setIntProperty(WMQConstants.WMQ_CLIENT_RECONNECT_TIMEOUT, MQConnectionDetails.RECONNECT_TIMEOUT);
    
    jcf.setClientReconnectOptions(WMQConstants.WMQ_CLIENT_RECONNECT);
    jcf.setClientReconnectTimeout(MQConnectionDetails.RECONNECT_TIMEOUT);
    
    package com.raiks.mqclient;
    
    import javax.jms.Destination;
    import javax.jms.JMSConsumer;
    import javax.jms.JMSContext;
    import javax.jms.JMSException;
    
    import com.ibm.msg.client.jms.JmsConnectionFactory;
    import com.ibm.msg.client.wmq.WMQConstants;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import com.raiks.mqclient.IbmMqMessageListener;
    
    /**
     * This class implements the reconnection logic for JMS brokers that don't support it
     * In particular, it does it for IBM MQ with its incomprehensible reconnection algorithm
     * It's expected that each connection manager receives a separate connection factory
     * and a message listener - it's not guaranteed for those to be thread safe
     */
    public final class IbmMqJmsConnectionManager {
        private static final Logger LOGGER = LoggerFactory.getLogger(IbmMqJmsConnectionManager.class);
        private static final int INITIAL_RECONNECTION_DELAY_MS = 6000;
        private static final int MAX_RECONNECTION_DELAY_MS = 60000;
        private static final String QUEUE_PREIX = "queue:///";
    
        private final String connectorName;
        private final JmsConnectionFactory connectionFactory;
        private final String queueName;
    
        private final IbmMqMessageListener messageListener;
    
        private final int initialReconnectionDelayMs;
        private final int maxReconnectionDelayMs;
    
        public IbmMqJmsConnectionManager(
            String connectorName,
            JmsConnectionFactory connectionFactory,
            String queueName,
            IbmMqMessageListener messageListener,
            int initialReconnectionDelayMs,
            int maxReconnectionDelayMs
        ) {
            this.connectorName = connectorName;
            this.connectionFactory = connectionFactory;
            this.queueName = queueName;
            this.messageListener = messageListener;
            this.initialReconnectionDelayMs = initialReconnectionDelayMs;
            this.maxReconnectionDelayMs = maxReconnectionDelayMs;
        }
    
        /**
         * Attempts to connect to a JMS broker and makes continuous retries with an increasing interval if fails
         * When the maximum interval is reached, issues an error and keeps on trying
         * Sets the exception listener (a callback) in the created JMSContext which calls this method when the
         * connection with the broker goes down due to network issue or intentional connection termination
         */
        public void connectToBrokerWithRetries() {
            String connectionDetails = formatConnectionDetails();
            LOGGER.info("Attempting to connect to JMS broker '{}'. Connection details = {}", connectorName, connectionDetails);
    
            JMSContext context = null;
            int sleepingTimeMs = INITIAL_RECONNECTION_DELAY_MS;
            int accumulatedSleepingTimeMs = 0;
    
            // Try to reconnect until we succeed. IMPORTANT! This is a blocking loop that never ends so it must be run in a separate thread
            while (context == null) {
                try {
                    context = connectionFactory.createContext(JMSContext.AUTO_ACKNOWLEDGE);
                    LOGGER.info("Successfully connected to the JMS broker '{}'. Connection details = {}", connectorName, connectionDetails);
    
                    boolean hadUnsuccessfulConnectionAttempts = accumulatedSleepingTimeMs > 0;
                    if (hadUnsuccessfulConnectionAttempts) {
                        LOGGER.warn(
                            "Before this successful attempt, I spent {} ms repeatedly trying to connect to '{}'. Please check the broker's health. Connection details = {}",
                            accumulatedSleepingTimeMs, connectorName, connectionDetails
                        );
                    }
    
                    Destination destination = context.createQueue(QUEUE_PREIX + queueName);
                    JMSConsumer jmsConsumer = context.createConsumer(destination);
                    jmsConsumer.setMessageListener(messageListener);
                    LOGGER.info("Successfully connected to the queue '{}' at '{}'. Connection details = {}", queueName, connectorName, connectionDetails);
    
                    // Sets a callback that will be invoked when something happens with a connection to a broker
                    context.setExceptionListener(
                        jmsException -> {
                            LOGGER.warn("Something bad happened to JMS broker connection to '{}'. I will try to reconnect. Connection details = {}", connectorName, connectionDetails);
                            connectToBrokerWithRetries();
                        }
                    );
                } catch (Exception e) {
                    LOGGER.warn(
                        "Failed to create a JMS context for '{}'. I will wait for {} ms and then make a reconnection attempt. Connection details = {}",
                        connectorName, sleepingTimeMs, connectionDetails, e
                    );
                    context = null;
                    try {
                        Thread.sleep(sleepingTimeMs);
                        accumulatedSleepingTimeMs += sleepingTimeMs;
                        int doubledSleepingTime = sleepingTimeMs * 2;
                        // We double the sleeping time on each subsequent attempt until we hit the limit
                        // Then we just keep on reconnecting forever using the limit value
                        boolean nextReconnectionDelayWillExceedMaxDelay = doubledSleepingTime >= MAX_RECONNECTION_DELAY_MS;
                        if (nextReconnectionDelayWillExceedMaxDelay) {
                            sleepingTimeMs = MAX_RECONNECTION_DELAY_MS;
                            LOGGER.error(
                                "Repeatedly failed to create a JMS context for {} ms. I will keep on trying every {} ms but please check the broker availability. Connection details = {}",
                                accumulatedSleepingTimeMs, sleepingTimeMs, connectionDetails
                            );
                        } else {
                            sleepingTimeMs = doubledSleepingTime;
                        }
                    } catch (InterruptedException ex) {
                        throw new RuntimeException(ex);
                    }
                }
            }
        }
    
        private String formatConnectionDetails() {
            String connectionDetails = "[]";
            try {
                connectionDetails = String.format(
                    "[ host = %s, port = %d, queueManager = %s, channel = %s, user = %s ]",
                    connectionFactory.getStringProperty(WMQConstants.WMQ_HOST_NAME),
                    connectionFactory.getIntProperty(WMQConstants.WMQ_PORT),
                    connectionFactory.getStringProperty(WMQConstants.WMQ_QUEUE_MANAGER),
                    connectionFactory.getStringProperty(WMQConstants.WMQ_CHANNEL),
                    connectionFactory.getStringProperty(WMQConstants.USERID)
                );
            } catch (Exception e) {
                LOGGER.warn("Failed to get the connection details. This is not critical, but the details will be unavailable");
            }
            return connectionDetails;
        }
    }
    
    LOGGER.info("Starting the initial connection thread");
    Thread cftInitialConnectionThread = new Thread(cftConnectionManager::connectToBrokerWithRetries);
    cftInitialConnectionThread.start();