C# MSMQ Receive()方法超时

C# MSMQ Receive()方法超时,c#,.net,timeout,msmq,C#,.net,Timeout,Msmq,不久前我最初的问题是,然而我已经从中进步,现在我想我对这个问题的了解更清楚了一点 我的代码(实际上是我正在使用的开源库的一部分)如下所示: queue.Receive(TimeSpan.FromSeconds(10), MessageQueueTransactionType.Automatic); class MSMQListener { public void StartListening(string queuePath) { MessageQueue ms

不久前我最初的问题是,然而我已经从中进步,现在我想我对这个问题的了解更清楚了一点

我的代码(实际上是我正在使用的开源库的一部分)如下所示:

queue.Receive(TimeSpan.FromSeconds(10), MessageQueueTransactionType.Automatic);
class MSMQListener
{
    public void StartListening(string queuePath)
    {
        MessageQueue msQueue = new MessageQueue(queuePath);
        msQueue.ReceiveCompleted += QueueMessageReceived;
        msQueue.BeginReceive();
    }

    private void QueueMessageReceived(object source, ReceiveCompletedEventArgs args)
    {
        MessageQueue msQueue = (MessageQueue)source;

        //once a message is received, stop receiving
        Message msMessage = null;
        msMessage = msQueue.EndReceive(args.AsyncResult);

        //do something with the message

        //begin receiving again
        msQueue.BeginReceive();
    }
}
它正在使用函数,队列是MessageQueue。问题如下

将使用指定的超时(10秒)调用上述代码行。
Receive(…)
函数是一个阻塞函数,应该一直阻塞,直到消息到达队列中,此时它将返回。如果在达到超时之前没有收到任何消息,它将在超时时返回。如果调用函数时队列中有消息,它将立即返回该消息

然而,正在发生的是调用
Receive(…)
函数,看到队列中没有消息,因此等待新消息进入。当一条新消息进来时(在超时之前),它没有检测到这条新消息并继续等待。超时最终会被触发,此时代码继续并再次调用
Receive(…)
,在那里它拾取消息并处理它

现在,这个问题只会在数天/数周后发生。我可以通过删除并重新创建队列使其再次正常工作。它发生在不同的计算机和不同的队列上。因此,似乎有什么东西正在积累,直到某个时候它破坏了
Receive(…)
函数使用的触发/通知功能

我检查了很多不同的东西,一切都正常&与正常工作的队列没有什么不同。有足够的磁盘空间(13gig可用)和RAM(据我所知,1GB中大约有350MB可用)。我检查了所有与其他队列相同的注册表项,并且性能监视器没有显示任何异常。我还运行了TMQ工具,从中看不出任何明显的错误

我在所有的机器上都使用Windows XP,它们都安装了service pack 3。我没有向队列发送大量消息,最多是每2秒发送1条,但通常频率要低得多。这些消息太小,远未达到4MB的限制

我刚才注意到的唯一一件事是C:\WINDOWS\system32\msmq\storage中的p000001.mq和r0000067.mq文件都是4096kb,但是在其他当前没有遇到此问题的计算机上也是如此大小。这个问题不会一次发生在计算机上的每个队列上,因为我可以在计算机上重新创建一个问题队列,而其他队列仍然会遇到这个问题

我对MSMQ不是很有经验,所以如果你发布了一些可能需要检查的东西,请你解释一下如何检查它们,或者我可以在哪里找到关于你所说内容的更多细节

目前的情况是:

  • ComputerA-4队列正常
  • 计算机B-2个队列遇到问题,1个队列正常
  • ComputerC-2队列遇到问题
  • 计算机D-1队列正常
  • ComputerE-2队列正常
因此,我有大量的计算机/队列可供比较和测试。

试试这个

公共消息接收(TimeSpan超时,光标)

重载函数

要获取MessageQueue的游标,请调用该队列的CreateCursor方法

当您需要读取不在队列前面的消息时,游标与Peek(TimeSpan,Cursor,PeekAction)和Receive(TimeSpan,Cursor)等方法一起使用。这包括同步或异步读取消息。不需要使用游标来读取队列中的第一条消息

在事务中读取消息时,如果事务中止,消息队列不会回滚光标移动。例如,假设有一个包含两条消息的队列,A1和A2。如果在事务中删除消息A1,消息队列会将光标移动到消息A2。但是,如果事务因任何原因而中止,则消息A1将被插入回队列中,但光标仍指向消息A2


要关闭光标,请调用close。

您没有使用事件处理程序侦听队列的任何特定原因?消息传递库允许您将处理程序附加到队列,而不是(如果我理解您的操作正确的话)每10秒循环接收一次。试着这样做:

queue.Receive(TimeSpan.FromSeconds(10), MessageQueueTransactionType.Automatic);
class MSMQListener
{
    public void StartListening(string queuePath)
    {
        MessageQueue msQueue = new MessageQueue(queuePath);
        msQueue.ReceiveCompleted += QueueMessageReceived;
        msQueue.BeginReceive();
    }

    private void QueueMessageReceived(object source, ReceiveCompletedEventArgs args)
    {
        MessageQueue msQueue = (MessageQueue)source;

        //once a message is received, stop receiving
        Message msMessage = null;
        msMessage = msQueue.EndReceive(args.AsyncResult);

        //do something with the message

        //begin receiving again
        msQueue.BeginReceive();
    }
}

我们也在使用NServiceBus,在我们的网络中也有类似的问题

基本上,MSMQ使用UDP进行两阶段提交。收到消息后,必须对其进行确认。在确认之前,无法在客户端接收,因为接收事务尚未完成

这是由不同时代的不同事物造成的:

  • 曾经,这是由于分布式事务协调器由于防火墙配置错误而无法在机器之间通信
  • 另一次,我们使用了没有sysprep的克隆虚拟机,这使得内部MSMQ ID不唯一,并使其接收到一台机器的消息和另一台机器的确认。最终,MSMQ解决了问题,但这需要相当长的时间

如果您想使用完全同步且无事件的东西,可以测试此方法

public object Receive(string path, int millisecondsTimeout)
{
    var mq = new System.Messaging.MessageQueue(path);
    var asyncResult = mq.BeginReceive();
    var handles = new System.Threading.WaitHandle[] { asyncResult.AsyncWaitHandle };
    var index = System.Threading.WaitHandle.WaitAny(handles, millisecondsTimeout);
    if (index == 258) // Timeout
    {
        mq.Close();
        return null;
    }
    var result = mq.EndReceive(asyncResult);
    return result;
}

什么是开源库?这是他们方面的一个已知问题吗?这是NServiceBus(www.NServiceBus.com)。似乎没有其他人经历过这个问题(至少邮件列表上没有人经历过)。我对其工作原理的解释是基于所有者对其的描述。NServiceBus线程在处理完前一条消息后(或在启动时)窥视队列中的消息。窥视的常规行为是阻止消息到达,但NServiceBus通过超时来限制该行为,以便允许