订阅者的IBM MQ重新连接逻辑

时间:2017-06-29 03:46:05

标签: c# ibm-mq mq xms

我有一个Windows服务,它将订阅队列并持续处理消息。除了重新连接逻辑之外,每件事都有效。我在我的代码中使用IBM.XMS.dll版本8。

当IBM Websphere MQ服务器发生故障转移时,我在重新建立订阅时遇到问题。在故障转移期间,我得到以下异常:

IBM.XMS.IllegalStateException: XMSCC0026
XMSCC0026.explanation
XMSCC0026.useraction
   at IBM.XMS.Client.Impl.State.CheckNotClosed(String message)
   at IBM.XMS.Client.Impl.XmsMessageProducerImpl.Send_(Boolean inIdentifiedContext, XmsDestinationImpl dest, IMessage message, DeliveryMode deliveryMode, Int32 priority, Int64 timeToLive, Boolean explicitDlvModePriorityAndTimeToLive)
   at IBM.XMS.Client.Impl.XmsMessageProducerImpl.Send(IMessage message)

Stack Trace:    at IBM.XMS.Client.Impl.State.CheckNotClosed(String message)
   at IBM.XMS.Client.Impl.XmsMessageProducerImpl.Send_(Boolean inIdentifiedContext, XmsDestinationImpl dest, IMessage message, DeliveryMode deliveryMode, Int32 priority, Int64 timeToLive, Boolean explicitDlvModePriorityAndTimeToLive)
   at IBM.XMS.Client.Impl.XmsMessageProducerImpl.Send(IMessage message)

我需要一些帮助来重新建立onException事件处理程序中的订阅:

private void ReconnectToXMS_MQ()
    {
        if (!_cancellationToken.IsCancellationRequested)
        {
            LoggingService.LogDebug($"[XMSQueue] Reconnecting for queue: {ConfigQueueName} and Address: {Address}");

            if(MsgQueueType == QueueType.Publisher)
            {
                Dispose(true);
                InitializeXMSMQ();
                InitialiseOutbound(ConfigQueueName, Pattern, false);
            }
            else if(MsgQueueType == QueueType.Subscriber)
            {
                //Need help here
            }
            else if(MsgQueueType == QueueType.Receiver)
            {
                Dispose(true);
                InitializeXMSMQ();
                InitialiseInbound(ConfigQueueName, Pattern, false);
            }
        }
    }

以下是我的XMS实施的完整代码段。

internal class XMSQueue : MessageQueueBase
{
    #region " Local Methods/Properties "

    private IConnectionFactory _connectionfactory;
    private IConnection _connection;
    private IDestination _destination;
    private ISession _session;
    private IMessageConsumer _consumer;
    private IMessageProducer _producer;
    private CancellationToken _cancellationTOke;

    private string ConfigQueueName { get; set; }

    private XMSProperties xmsConfiguration { get; set; }

    private MessageFormat MsgFormat { get; set; }

    private QueueType MsgQueueType { get; set; }

    #endregion

    #region " MessageQueueBase OVerrides "

    public override string Name { get; set; }


    #region " Receive/Subscribe "

    public override void InitialiseInbound(string name, MessagePattern pattern, bool isTemporary)
    {
        try
        {
            ConfigQueueName = name;
            Initialise(Direction.Inbound, name, pattern, isTemporary);

            InitializeXMSMQ();

            //Set Destination
            _destination = CreateDestinationInbound();

            //Create Consumer
            _consumer = _session.CreateConsumer(_destination);

        }
        catch (XMSException xmsError)
        {
            LogXMSExceptionDetails(xmsError);
            throw xmsError;
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

    public override void Subscribe<TReceiveMessageType>(Action<TReceiveMessageType> onMessageReceived, CancellationToken cancellationToken, MessageFormat messageFormat = MessageFormat.XMS_IMessage)
    {
        try
        {
            MsgQueueType = QueueType.Subscriber;
            _cancellationTOke = cancellationToken;
            cancellationToken.Register(() =>
            {
                _consumer.MessageListener = null;
            });

            MsgFormat = messageFormat;
            // Create and register the listener
            MessageListener messageListener = new MessageListener((msg) =>
            {
                TReceiveMessageType message;
                message = ProcessInboundMessage<TReceiveMessageType>(messageFormat, msg);
                onMessageReceived(message);

            });
            _consumer.MessageListener = messageListener;

            // Start the connection
            _connection.Start();
        }
        catch (XMSException xmsError)
        {
            LogXMSExceptionDetails(xmsError);

            ReconnectToXMS_MQ();
        }
        catch (Exception ex)
        {
            ReconnectToXMS_MQ();
        }
    }

    public override void Receive<TReceiveMessageType>(Action<TReceiveMessageType> onMessageReceived, bool processAsync, int maximumWaitMilliseconds = 0, MessageFormat messageFormat = MessageFormat.XMS_IMessage)
    {
        try
        {
            MsgQueueType = QueueType.Receiver;
            MsgFormat = messageFormat;
            // Start the connection
            _connection.Start();

            IMessage inbound = null;
            TReceiveMessageType message;

            // Receive the message                                    
            inbound = _consumer.Receive();
            if (inbound != null)
            {
                message = ProcessInboundMessage<TReceiveMessageType>(messageFormat, inbound);

                if (processAsync)
                {
                    Task.Factory.StartNew(() => onMessageReceived(message));
                }
                else
                {
                    onMessageReceived(message);
                }
            }
            else
            {
                throw new Exception("Message received was null.");
            }
        }
        catch (XMSException xmsError)
        {
            LogXMSExceptionDetails(xmsError);
            throw xmsError;
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

    #endregion

    #region " Send/Publish "

    public override void InitialiseOutbound(string name, MessagePattern pattern, bool isTemporary)
    {
        try
        {
            ConfigQueueName = name; //Save the config queue name for later use in reconnection logic
            Initialise(Direction.Outbound, name, pattern, isTemporary);

            InitializeXMSMQ();

            //Set Destination
            _destination = CreateDestinationOutbound();

            //Create Producer
            _producer = _session.CreateProducer(_destination);

        }
        catch (XMSException xmsError)
        {
            LogXMSExceptionDetails(xmsError);
            throw xmsError;
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

    public override bool Send<T>(T message, MessageFormat messageFormat)
    {
        try
        {
            MsgQueueType = QueueType.Publisher;
            MsgFormat = messageFormat;
            //Start the connection
            _connection.Start();

            //Create Message
            IMessage outbound = null;
            if (messageFormat == MessageFormat.String)
            {
                outbound = _session.CreateTextMessage(message.ToString());
            }
            else if (messageFormat == MessageFormat.ByteArray)
            {
                outbound = _session.CreateObjectMessage();
                byte[] byteText = message as byte[];
                ((IObjectMessage)outbound).SetObject(byteText);
            }
            else if (messageFormat == MessageFormat.XMS_IMessage)
            {
                outbound = message as IMessage;
            }
            else
            {
                throw new NotSupportedException("UnRecognized/UnSUpported message format. Please use String, ByteArray or XMS_IMessage message formats");
            }

            _producer.Send(outbound);
            return true;
        }
        catch (XMSException xmsError)
        {
            LogXMSExceptionDetails(xmsError);
            return false;
        }
        catch (Exception ex)
        {
            return false;
        }
    }

    #endregion

    protected override void Dispose(bool disposing)
    {
        try
        {
            if (_consumer != null)
            {
                _consumer.Close();
                _consumer.Dispose();
            }

            //Reset Producer
            if (_producer != null)
            {
                _producer.Close();
                _producer.Dispose();
            }

            //Reset Destination
            if (_destination != null)
                _destination.Dispose();

            //Reset Session
            if (_session != null)
            {
                _session.Close();
                _session.Dispose();
            }

            //Reset Connection
            if (_connection != null)
            {
                _connection.Close();
                _consumer.Dispose();
            }
        }
        catch (Exception)
        {
            //ignore any exceptions at this point
        }
    }

    #endregion

    #region " Local Methods "

    #region " Initialize and Reconnect "

    private void InitializeXMSMQ()
    {
        xmsConfiguration = new XMSProperties(Properties);
        xmsConfiguration.ConnectionType = RequirePropertyValue(ConfigurationKeys.ConnectionType);

        //SetConnectionFactory Connection Factory
        SetConnectionFactory();

        //Set Connection
        _connection = _connectionfactory.CreateConnection(null, null); //We do not use UserID and Password to connect.
        _connection.ExceptionListener = new ExceptionListener(OnConnectionException);

        //Set Session
        _session = _connection.CreateSession(false, AcknowledgeMode.AutoAcknowledge);
    }

    private void ReconnectToXMS_MQ()
    {
        if (!_cancellationTOke.IsCancellationRequested)
        {
            if(MsgQueueType == QueueType.Publisher)
            {
                Dispose(true);
                InitializeXMSMQ();
                InitialiseOutbound(ConfigQueueName, Pattern, false);
            }
            else if(MsgQueueType == QueueType.Subscriber)
            {
                //Need help here
            }
            else if(MsgQueueType == QueueType.Receiver)
            {
                Dispose(true);
                InitializeXMSMQ();
                InitialiseInbound(ConfigQueueName, Pattern, false);
            }
        }
    }

    private void OnConnectionException(Exception ex)
    {
        ReconnectToXMS_MQ();
    }

    private static void LogXMSExceptionDetails(XMSException xmsError)
    {
        if (xmsError.LinkedException != null)
        {
            LogError($"[XMSQueue] Linked Exception: {xmsError.LinkedException.Message} ");
            if (xmsError.LinkedException.InnerException != null)
                LogError($"[XMSQueue] Linked Inner Exception: {xmsError.LinkedException.InnerException} ");
        }
    }

    #endregion

    #region " XMS Connection Factory "
    private void SetConnectionFactory()
    {
        _connectionfactory = CreateConnectionFactory();
    }

    private IConnectionFactory CreateConnectionFactory()
    {
        IConnectionFactory iConnFact;
        switch (xmsConfiguration.ConnectionType.ToUpper())
        {
            // WPM connection factory
            case "WPM":
                iConnFact = CreateConnectionFactoryWPM();
                break;
            // RTT connection factory
            case "RTT":
                iConnFact = CreateConnectionFactoryRTT();
                break;
            // WMQ connection factory
            case "WMQ":
                iConnFact = CreateConnectionFactoryWMQ();
                break;
            default:
                iConnFact = null;
                break;
        }
        return iConnFact;
    }

    /// <summary>
    /// Create a WPM connection factory and set relevant properties.
    /// </summary>
    /// <returns>A connection factory</returns>
    private static IConnectionFactory CreateConnectionFactoryWPM()
    {
        // Create the connection factories factory
        XMSFactoryFactory factoryFactory = XMSFactoryFactory.GetInstance(XMSC.CT_WPM);

        // Use the connection factories factory to create a connection factory
        IConnectionFactory cf = factoryFactory.CreateConnectionFactory();


        // WPM multicast is currently disabled
        // cf.SetIntProperty(XMSC.WPM_MULTICAST, Options.MulticastModeWPM.ValueAsNumber);

        return (cf);
    }

    /// <summary>
    /// Create a RTT connection factory and set relevant properties.
    /// </summary>
    /// <returns>A connection factory</returns>
    private static IConnectionFactory CreateConnectionFactoryRTT()
    {
        // Create the connection factories factory
        XMSFactoryFactory factoryFactory = XMSFactoryFactory.GetInstance(XMSC.CT_RTT);

        // Use the connection factories factory to create a connection factory
        IConnectionFactory cf = factoryFactory.CreateConnectionFactory();

        return (cf);
    }

    /// <summary>
    /// Create a WMQ connection factory and set relevant properties.
    /// </summary>
    /// <returns>A connection factory</returns>
    private IConnectionFactory CreateConnectionFactoryWMQ()
    {
        // Create the connection factories factory
        XMSFactoryFactory factoryFactory = XMSFactoryFactory.GetInstance(XMSC.CT_WMQ);

        // Use the connection factories factory to create a connection factory
        IConnectionFactory cf = factoryFactory.CreateConnectionFactory();

        // Set the properties
        cf.SetStringProperty(XMSC.WMQ_HOST_NAME, xmsConfiguration.WMQProperties.Hostname);
        cf.SetIntProperty(XMSC.WMQ_PORT, xmsConfiguration.WMQProperties.Port);
        cf.SetStringProperty(XMSC.WMQ_CHANNEL, xmsConfiguration.WMQProperties.Channel);
        cf.SetIntProperty(XMSC.WMQ_CONNECTION_MODE, xmsConfiguration.WMQProperties.ConnectionMode);
        if (string.IsNullOrEmpty(xmsConfiguration.WMQProperties.QueueManager))
        {
            cf.SetStringProperty(XMSC.WMQ_QUEUE_MANAGER, "");
        }
        else
        {
            cf.SetStringProperty(XMSC.WMQ_QUEUE_MANAGER, xmsConfiguration.WMQProperties.QueueManager);
        }

        if (xmsConfiguration.WMQProperties.BrokerVersion != -1) //-1 => Not set in configuration
            cf.SetIntProperty(XMSC.WMQ_BROKER_VERSION, xmsConfiguration.WMQProperties.BrokerVersion);

        cf.SetStringProperty(XMSC.WMQ_CONNECTION_NAME_LIST, xmsConfiguration.WMQProperties.Hostname);
        if (!string.IsNullOrWhiteSpace(xmsConfiguration.WMQProperties.ConnectionList))
        {
            cf.SetStringProperty(XMSC.WMQ_CONNECTION_NAME_LIST, xmsConfiguration.WMQProperties.ConnectionList);
            cf.SetIntProperty(XMSC.WMQ_CLIENT_RECONNECT_TIMEOUT, xmsConfiguration.WMQProperties.ReconnectTimeout);
            cf.SetIntProperty(XMSC.WMQ_CLIENT_RECONNECT_OPTIONS, xmsConfiguration.WMQProperties.ReconnectOptions);
        }

        if (!string.IsNullOrWhiteSpace(xmsConfiguration.WMQProperties.SSLCertRepository))
        {
            cf.SetStringProperty(XMSC.WMQ_SSL_KEY_REPOSITORY, xmsConfiguration.WMQProperties.SSLCertRepository);
            cf.SetStringProperty(XMSC.WMQ_SSL_CIPHER_SPEC, xmsConfiguration.WMQProperties.SSLCipherSpec);
        }

        cf.SetStringProperty(XMSC.WMQ_PROVIDER_VERSION, XMSC.WMQ_PROVIDER_VERSION_DEFAULT);
        cf.SetBooleanProperty(XMSC.WMQ_SYNCPOINT_ALL_GETS, true);
        return (cf);
    }

    #endregion

    #region " Create IDestination "

    protected IDestination CreateDestinationOutbound()
    {
        IDestination iDest;

        switch (xmsConfiguration.ConnectionType.ToUpper())
        {
            // WPM destination
            case Literals.WPM:
            case Literals.WMQ:
                if (Pattern == MessagePattern.FireAndForget)
                {
                    iDest = (Address.StartsWith("queue://")) ?
                                _session.CreateQueue(Address) : // Create a Queue
                                _session.CreateTopic(Address);  // FireAndForget is defaulted to Topic for Outbound unless Address is defined with queue
                }
                else if (Pattern == MessagePattern.PublishSubscribe)
                {
                    iDest = (Address.StartsWith("queue://")) ?
                                _session.CreateQueue(Address) : // Create a Queue
                                _session.CreateTopic(Address);  // PublishSubscribe is defaulted to Topic for Outbound unless Address is defined with queue
                }
                else
                {
                    iDest = (Address.StartsWith("queue://")) ?
                                _session.CreateQueue(Address) : // Create a queue
                                _session.CreateTopic(Address);  // Otherwise, default to creating a topic
                }

                iDest.SetIntProperty(XMSC.DELIVERY_MODE, xmsConfiguration.WMQProperties.DeliveryMode);
                iDest.SetIntProperty(XMSC.WMQ_TARGET_CLIENT, xmsConfiguration.WMQProperties.TargetClient);
                break;

            // RTT destination
            case Literals.RTT:
                iDest = _session.CreateTopic(Address);  // Create a topic
                break;
            default:
                iDest = null;
                break;
        }
        return (iDest);
    }

    protected IDestination CreateDestinationInbound()
    {
        IDestination iDest;

        switch (xmsConfiguration.ConnectionType.ToUpper())
        {
            // WPM destination
            case Literals.WPM:
            case Literals.WMQ:
                if (Pattern == MessagePattern.FireAndForget)
                {
                    iDest = (Address.StartsWith("topic://")) ?
                                _session.CreateTopic(Address) : // Create a Topic
                                _session.CreateQueue(Address);  // FireAndForget is defaulted to Queues for Inbound unless Address is defined with topic
                }
                else if (Pattern == MessagePattern.PublishSubscribe)
                {
                    iDest = (Address.StartsWith("topic://")) ?
                                _session.CreateTopic(Address) : // Create a Topic
                                _session.CreateQueue(Address);  // PublishSubscribe is defaulted to Queue for Inbound unless Address is defined with topic
                }
                else
                {
                    iDest = (Address.StartsWith("topic://")) ?
                                _session.CreateTopic(Address) : // Create a Topic
                                _session.CreateQueue(Address);  // Otherwise, default to creating a Queue
                }

                iDest.SetIntProperty(XMSC.DELIVERY_MODE, xmsConfiguration.WMQProperties.DeliveryMode);
                iDest.SetIntProperty(XMSC.WMQ_TARGET_CLIENT, xmsConfiguration.WMQProperties.TargetClient);
                break;

            // RTT destination
            case Literals.RTT:
                iDest = _session.CreateQueue(Address);  // Create a Queue
                break;
            default:
                iDest = null;
                break;
        }
        return (iDest);
    }

    #endregion

    private static TReceiveMessageType ProcessInboundMessage<TReceiveMessageType>(MessageFormat messageFormat, IMessage inbound)
    {
        TReceiveMessageType message;
        if (messageFormat == MessageFormat.String)
        {
            ITextMessage txtMessage = (ITextMessage)inbound;
            message = (TReceiveMessageType)(object)txtMessage.Text;
        }
        else if (messageFormat == MessageFormat.ByteArray)
        {
            IObjectMessage inboundBytes = (IObjectMessage)inbound;
            byte[] body = inboundBytes.GetObject();

            message = (TReceiveMessageType)(object)body;
        }
        else if (messageFormat == MessageFormat.WMQ_MQMessage)
        {
            throw new NotSupportedException("MessageFormat.WMQ_MQMessage is not supported in IBM.XMS implementation. Please use String, ByteArray, Stream, Object (byte[]) or XMS_IMessage message formats");
        }
        else if (messageFormat == MessageFormat.XMS_IMessage)
        {
            message = (TReceiveMessageType)inbound;
        }
        else if (messageFormat == MessageFormat.Object)
        {
            IObjectMessage inboundObject = (IObjectMessage)inbound;
            byte[] body = inboundObject.GetObject();

            message = (TReceiveMessageType)(object)body;
        }
        else if (messageFormat == MessageFormat.Stream)
        {
            IObjectMessage inboundObject = (IObjectMessage)inbound;
            byte[] body = inboundObject.GetObject();

            MemoryStream streamBody = new MemoryStream(body);
            message = (TReceiveMessageType)(object)streamBody;
        }
        else
        {
            throw new NotSupportedException("UnRecognized message format. Please use String, ByteArray, Stream, Object (byte[]) or XMS_IMessage message formats");
        }

        return message;
    }

    #endregion        
}

0 个答案:

没有答案