.NET IBM MQ Listener未确认消息并从队列开头读取

时间:2016-06-14 14:16:24

标签: c# .net ibm-mq

我有一个C#应用程序,它设置了许多MQ侦听器(多个线程,可能还有多个服务器,每个服务器都有自己的侦听器)。有一些消息将从队列中消失,我将要留在队列中,转到MQ上的下一条消息,但在某些情况下我会想回去重新读取这些消息......

var connectionFactory = XMSFactoryFactory.GetInstance(XMSC.CT_WMQ).CreateConnectionFactory();
connectionFactory.SetStringProperty(XMSC.WMQ_HOST_NAME, origination.Server);
connectionFactory.SetIntProperty(XMSC.WMQ_PORT, int.Parse(origination.Port));
connectionFactory.SetStringProperty(XMSC.WMQ_QUEUE_MANAGER, origination.QueueManager);
connectionFactory.SetStringProperty(XMSC.WMQ_CHANNEL, origination.Channel);

var connection = connectionFactory.CreateConnection(null, null);
_connections.Add(connection);

var session = connection.CreateSession(false, AcknowledgeMode.ClientAcknowledge);   //changed to use ClientAcknowledge so that we will leave the message on the MQ until we're sure we're processing it
_sessions.Add(session);

var destination = session.CreateQueue(origination.Queue);
_destinations.Add(destination);

var consumer = session.CreateConsumer(destination);
_consumers.Add(consumer);

Logging.LogDebugMessage(Constants.ListenerStart);

connection.Start();
ThreadPool.QueueUserWorkItem((o) => Receive(forOrigination, consumer));

然后我......

if (OnMQMessageReceived != null)
{
    var message = consumer.Receive();
    var identifier = string.Empty;

    if (message is ITextMessage)
    {
        //do stuff with the message here
        //populates identifier from the message
    }
    else
    {
        //do stuff with the message here
        //populates identifier from the message
    }

    if (!string.IsNullOrWhiteSpace(identifier)&& OnMQMessageReceived != null)
    {
        if( some check to see if we should process the message now)
        {
            //process message here
            message.Acknowledge();  //this really pulls it off of the MQ

            //here is where I want to trigger the next read to be from the beginning of the MQ
        }
        else
        {
            //We actually want to do nothing here. As in do not do Acknowledge
            //This leaves the message on the MQ and we'll pick it up again later
            //But we want to move on to the next message in the MQ
        }
    }
    else
    {
        message.Acknowledge();  //this really pulls it off of the MQ...its useless to us anyways
    }
}
else
{
    Thread.Sleep(0);
}

ThreadPool.QueueUserWorkItem((o) => Receive(forOrigination, consumer));

所以有几个问题:

  1. 如果我不确认它留在MQ上的消息,对吗?

  2. 如果消息未被确认,那么默认情况下,当我再次使用相同的侦听器从MQ读取时,它会读取下一个并且不会到达开头,对吧?

  3. 如何更改监听器,以便下次读取时从队列开始处开始?

1 个答案:

答案 0 :(得分:2)

将消息留在队列中是一种反模式。如果您不想或不能在逻辑的某个点处理消息,那么您有多种选择:

  • 将其从队列中取出并放入另一个队列/主题以进行延迟/不同的处理。
  • 将其从队列中取出并转储到数据库,平面文件 - 无论如何,如果您想在消息流之外处理它,或者根本不想处理它。
  • 如果可行,您可能希望更改消息生成器,以便它不会在同一队列/主题中混合具有不同处理要求的消息。

在任何情况下,都不要在队列中留言,并始终前进到下一条消息。这将使应用程序更可预测,更容易推理。您还将避免各种性能问题。如果您的应用程序对邮件传递顺序敏感或可能变得敏感,那么手动确认所选邮件也会与之不一致。

问题:

  1. JMS规范对于未确认消息的行为是模糊的 - 它们可能无序传递,并且在确切地何时传递它们时是未定义的。此外,确认方法调用将确认所有以前收到和未确认的消息 - 可能不是您的想法。

  2. 如果您留言,听众可能会立即返回。如果你重新启动它,它当然会重新开始,但是当它坐在那里等待消息时它依赖于实现。

  3. 因此,如果你试图让你的设计工作,你可能会在某些情况下得到它的工作,但它不可预测或不可靠。