MSMQ Receive() method timeout

mike picture mike · Nov 25, 2009 · Viewed 12.8k times · Source

My original question from a while ago is MSMQ Slow Queue Reading, however I have advanced from that and now think I know the problem a bit more clearer.

My code (well actually part of an open source library I am using) looks like this:

queue.Receive(TimeSpan.FromSeconds(10), MessageQueueTransactionType.Automatic);

Which is using the Messaging.MessageQueue.Receive function and queue is a MessageQueue. The problem is as follows.

The above line of code will be called with the specified timeout (10 seconds). The Receive(...) function is a blocking function, and is supposed to block until a message arrives in the queue at which time it will return. If no message is received before the timeout is hit, it will return at the timeout. If a message is in the queue when the function is called, it will return that message immediately.

However, what is happening is the Receive(...) function is being called, seeing that there is no message in the queue, and hence waiting for a new message to come in. When a new message comes in (before the timeout), it isn't detecting this new message and continues waiting. The timeout is eventually hit, at which point the code continues and calls Receive(...) again, where it picks up the message and processes it.

Now, this problem only occurs after a number of days/weeks. I can make it work normally again by deleting & recreating the queue. It happens on different computers, and different queues. So it seems like something is building up, until some point when it breaks the triggering/notification ability that the Receive(...) function uses.

I've checked a lot of different things, and everything seems normal & isn't different from a queue that is working normally. There is plenty of disk space (13gig free) and RAM (about 350MB free out of 1GB from what I can tell). I have checked registry entries which all appear the same as other queues, and the performance monitor doesn't show anything out of the normal. I have also run the TMQ tool and can't see anything noticably wrong from that.

I am using Windows XP on all the machines and they all have service pack 3 installed. I am not sending a large amount of messages to the queues, at most it would be 1 every 2 seconds but generally a lot less frequent than that. The messages are only small too and nowhere near the 4MB limit.

The only thing I have just noticed is the p0000001.mq and r0000067.mq files in C:\WINDOWS\system32\msmq\storage are both 4,096KB however they are that size on other computers also which are not currently experiencing the problem. The problem does not happen to every queue on the computer at once, as I can recreate 1 problem queue on the computer and the other queues still experience the problem.

I am not very experienced with MSMQ so if you post possible things to check can you please explain how to check them or where I can find more details on what you are talking about.

Currently the situation is:

  • ComputerA - 4 queues normal
  • ComputerB - 2 queues experiencing problem, 1 queue normal
  • ComputerC - 2 queues experiencing problem
  • ComputerD - 1 queue normal
  • ComputerE - 2 queues normal

So I have a large number of computers/queues to compare and test against.

Answer

Mike Lorenzana picture Mike Lorenzana · Jan 17, 2014

Any particular reason you aren't using an event handler to listen to the queues? The System.Messaging library allows you to attach a handler to a queue instead of, if I understand what you are doing correctly, looping Receive every 10 seconds. Try something like this:

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();
    }
}