我有一个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
}