Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does MessageQueue.BeginReceive work and how to use it correctly?

I currently have a background thread. In this thread is a infinite loop.

This loop once in a while updates some values in a database, and then listens 1 second on the MessageQueue (with queue.Receive(TimeSpan.FromSeconds(1)) ).

As long as no message comes in, this call then internally throws a MessageQueueException (Timeout) which is caught and then the loop continues. If there is a message the call normally returns and the message is processed, after which the loop continues.

This leads to a lot of First chance exceptions (every second, except there is a message to process) and this spams the debug output and also breaks in the debugger when I forgot to exclude MessageQueueExceptions.

So how is the async handling of the MessageQueue meant to be done correctly, while still ensuring that, as long as my application runs, the queue is monitored and the database is updated too once in a while. Of course the thread here should not use up 100% CPU.

I just need the big picture or a hint to some correctly done async processing.

like image 484
Sebastian P.R. Gingter Avatar asked Dec 21 '22 08:12

Sebastian P.R. Gingter


2 Answers

Rather than looping in a thread, I would recommend registering a delegate for the ReceiveCompleted event of your MessageQueue, as described here:

using System; using System.Messaging;

namespace MyProject { /// /// Provides a container class for the example. /// public class MyNewQueue {

    //**************************************************
    // Provides an entry point into the application.
    //       
    // This example performs asynchronous receive operation
    // processing.
    //**************************************************

    public static void Main()
    {
        // Create an instance of MessageQueue. Set its formatter.
        MessageQueue myQueue = new MessageQueue(".\\myQueue");
        myQueue.Formatter = new XmlMessageFormatter(new Type[]
            {typeof(String)});

        // Add an event handler for the ReceiveCompleted event.
        myQueue.ReceiveCompleted += new 
            ReceiveCompletedEventHandler(MyReceiveCompleted);

        // Begin the asynchronous receive operation.
        myQueue.BeginReceive();

        // Do other work on the current thread.

        return;
    }


    //**************************************************
    // Provides an event handler for the ReceiveCompleted
    // event.
    //**************************************************

    private static void MyReceiveCompleted(Object source, 
        ReceiveCompletedEventArgs asyncResult)
    {
        // Connect to the queue.
        MessageQueue mq = (MessageQueue)source;

        // End the asynchronous Receive operation.
        Message m = mq.EndReceive(asyncResult.AsyncResult);

        // Display message information on the screen.
        Console.WriteLine("Message: " + (string)m.Body);

        // Restart the asynchronous Receive operation.
        mq.BeginReceive();

        return; 
    }
}

}

Source: https://learn.microsoft.com/en-us/dotnet/api/system.messaging.messagequeue.receivecompleted?view=netframework-4.7.2

like image 184
DaveRead Avatar answered Dec 24 '22 02:12

DaveRead


Have you considered a MessageEnumerator which is returned from the MessageQueue.GetMessageEnumerator2 ?

  • You get a dynamic content of the queue to examine and remove messages from a queue during the iteration.
  • If there are no messages then MoveNext() will return false and you don't need to catch first-chance exceptions
  • If there are new messages after you started iteration then they will be iterated over (if they are put after a cursor).
  • If there are new messages before a cursor then you can just reset an iterator or continue (if you don't need messages with lower priority at the moment).
like image 42
Andrey Taptunov Avatar answered Dec 24 '22 01:12

Andrey Taptunov