Search code examples
c#ibm-mq

C# API for MQ Listener - Automatic reconnect


I have an application that listens to an IBM message queue that I do not control.

There are situations where the message queue is restarted and my connection to the queue is lost.

Right now, I'm using an exception listener to kill the process on any kind of connection exception and the Windows Task Scheduler then restarts the process. This works, but it feels like using dynamite to hammer in a nail. I'm told there is a more elegant way to deal with this, but based on my understanding of IBM's MQ documentation, the reconnect ability is only available for WebSphere applications, which I am not using. My efforts to simply reinitialize the app on an exception aren't actually reconnecting me to the message queue correctly.

This is the method I use to init the connection.

public static MessageQueue Init(MessageListener listener, ExceptionListener exl)
    {
        var queueSettings = ServiceConfig.Settings.MessageQueue;

        XMSFactoryFactory xff = XMSFactoryFactory.GetInstance(XMSC.CT_WMQ);
        IConnectionFactory cf = xff.CreateConnectionFactory();
        cf.SetStringProperty(XMSC.WMQ_HOST_NAME, queueSettings.HostName);
        cf.SetIntProperty(XMSC.WMQ_PORT, queueSettings.Port);
        cf.SetStringProperty(XMSC.WMQ_CHANNEL, queueSettings.Channel);
        cf.SetIntProperty(XMSC.WMQ_CONNECTION_MODE, XMSC.WMQ_CM_CLIENT);
        cf.SetStringProperty(XMSC.WMQ_QUEUE_MANAGER, queueSettings.QManagerName);
        cf.SetStringProperty(XMSC.USERID, queueSettings.UserId);
        cf.SetStringProperty(XMSC.PASSWORD, queueSettings.Password);
        cf.SetIntProperty(XMSC.WMQ_BROKER_VERSION, XMSC.WMQ_BROKER_V1);

        // connect to MQ Server
        //Log.Logger.Information($"Creating MessageQueue Connection [{service}]...");

        var conn = cf.CreateConnection();
        Log.Logger.Information("MessageQueue Connection Succesfully Created");
        conn.ExceptionListener = exl;
        ISession sess = conn.CreateSession(false, AcknowledgeMode.AutoAcknowledge);
        IDestination dest = sess.CreateQueue(queueSettings.QueueName);
        IMessageConsumer consumer = sess.CreateConsumer(dest);
        IMessageProducer producer = sess.CreateProducer(dest);
        MessageListener ml = new MessageListener(listener);
        ExceptionListener el = new ExceptionListener(exl);
        consumer.MessageListener = ml;

        return new MessageQueue()
        {
            Connection = conn,
            MessageListener = ml,
            ExceptionListener = exl,
            Session = sess
        };
    }

And this is the method that fires when I see an exception:

public void OnEventException(Exception ex)
    {
        _logger.Error("CONNECTION ERROR DETECTED");
        _logger.Error((ex.Message != null) ? ex.Message : string.Empty);
        _logger.Error((ex.StackTrace != null) ? ex.StackTrace : string.Empty);
        Environment.Exit(1);
    }

Is there a simpler/more elegant way to do this?


Solution

  • I have reproduced here the snippet from SampleAutoReconnect sample shipped with the product. Hope this is helpful.

        private void ClientAutoReconnect()
        {
            XMSFactoryFactory factoryFactory;
            IConnectionFactory cf;
            IConnection connectionWMQ;
            ISession sessionWMQ;
            IDestination destination;
            IMessageConsumer messageConsumer;
            IMessageProducer messageProducer;
            
            // Get an instance of factory.
            factoryFactory = XMSFactoryFactory.GetInstance(XMSC.CT_WMQ);
    
            // Create WMQ Connection Factory.
            cf = factoryFactory.CreateConnectionFactory();
            Console.WriteLine("Connection Factory created.");
    
            // Set the connection properties
            cf.SetIntProperty(XMSC.WMQ_CONNECTION_MODE, XMSC.WMQ_CM_CLIENT);
            cf.SetStringProperty(XMSC.WMQ_CONNECTION_NAME_LIST, "myqmhost(1414)");
            cf.SetStringProperty(XMSC.WMQ_CHANNEL, "SVR_RECONN_CHL");
            cf.SetIntProperty(XMSC.WMQ_CLIENT_RECONNECT_TIMEOUT, 3600);
    
            // set the reconnect option
           cf.SetIntProperty(XMSC.WMQ_CLIENT_RECONNECT_OPTIONS, XMSC.WMQ_CLIENT_RECONNECT);
            
            // Create connection.
            connectionWMQ = cf.CreateConnection();
            Console.WriteLine("Connection created.");
    
            Console.WriteLine("The resolved queue manager is - " + connectionWMQ.GetStringProperty(XMSC.WMQ_RESOLVED_QUEUE_MANAGER));
    
            connectionWMQ.ExceptionListener = new ExceptionListener(OnException);
            Console.WriteLine("Exception listener registered");
    
            // Create session
            sessionWMQ = connectionWMQ.CreateSession(false, AcknowledgeMode.AutoAcknowledge);
            Console.WriteLine("Session created.");}