How can I subscribe to an MSMQ queue but only "peep" into a .Net message?

We have an MSMQ queue setup that receives messages and is processed by the application. We would like another process to subscribe to the queue, and just read the message and write its contents.

I already have this, the problem is that it constantly looks into the queue. The CPU on the server when it is running is about 40%. Mqsvc.exe runs at 30% and this application runs at 10%. I would prefer something that just waits for a message to come in, gets notified about it, and then logs it without polling the server constantly.

    Dim lastid As String
    Dim objQueue As MessageQueue
    Dim strQueueName As String

    Public Sub Main()
        objQueue = New MessageQueue(strQueueName, QueueAccessMode.SendAndReceive)
        Dim propertyFilter As New MessagePropertyFilter
        propertyFilter.ArrivedTime = True
        propertyFilter.Body = True
        propertyFilter.Id = True
        propertyFilter.LookupId = True
        objQueue.MessageReadPropertyFilter = propertyFilter
        objQueue.Formatter = New ActiveXMessageFormatter
        AddHandler objQueue.PeekCompleted, AddressOf MessageFound

        objQueue.BeginPeek()
    end main

    Public Sub MessageFound(ByVal s As Object, ByVal args As PeekCompletedEventArgs)

        Dim oQueue As MessageQueue
        Dim oMessage As Message

        ' Retrieve the queue from which the message originated
        oQueue = CType(s, MessageQueue)

            oMessage = oQueue.EndPeek(args.AsyncResult)
            If oMessage.LookupId <> lastid Then
                ' Process the message here
                lastid = oMessage.LookupId
                ' let write it out
                log.write(oMessage)
            End If

        objQueue.BeginPeek()
    End Sub

      

+2


a source to share


5 answers


A Thread.Sleep (10) between peeking iterations can save you a bunch of loops.



The only other possibility I can think of is to create logging in a queue reader application.

+3


a source


Have you tried using MSMQEvent.Arrived to track messages?



An inbound event on an MSMQEvent is fired when the MSMQQueue.EnableNotification method of an instance of an MSMQQueue object representing an open queue has been called and a message has been found or arrives at the appropriate position in the queue.

+4


a source


There is no API that will allow you to look at each message only once.

The problem is that it BeginPeek

executes the callback immediately if there is already a message in the queue. Since you are not deleting the message (this is peeking after all, don't accept!), When your callback starts peeking again, the process starts, so it MessageFound

runs almost constantly.

Your best options are to write messages to the writer or reader. Logging will work for short periods of time (if you only care about the messages received), but is not a long-term solution:

While the performance overhead of fetching messages from a queue that is configured for logging is only about 20% greater than fetching a message without logging, the real costs are unexpected problems caused when an unverified MSMQ service is started from memory or on a computer no disk space

+1


a source


This works for me. It blocks the thread while waiting for a message. Each loop of the loop checks a class member _bServiceRunning

to see if the thread should be interrupted.

    private void ProcessMessageQueue(MessageQueue taskQueue)
    {
        // Set the formatter to indicate body contains a binary message:
        taskQueue.Formatter = new BinaryMessageFormatter();

        // Specify to retrieve selected properties.
        MessagePropertyFilter myFilter = new MessagePropertyFilter();
        myFilter.SetAll();
        taskQueue.MessageReadPropertyFilter = myFilter;

        TimeSpan tsQueueReceiveTimeout = new TimeSpan(0, 0, 10); // 10 seconds

        // Monitor the MSMQ until the service is stopped:
        while (_bServiceRunning)
        {
            rxMessage = null;

            // Listen to the queue for the configured duration:
            try
            {
                // See if a message is available, and if so remove if from the queue if any required
                // web service is available:
                taskQueue.Peek(tsQueueReceiveTimeout);

                // If an IOTimeout was not thrown, there is a message in the queue
                // Get all the messages; this does not remove any messages
                Message[] arrMessages = taskQueue.GetAllMessages();

                // TODO: process the message objects here;
                //       they are copies of the messages in the queue
                //       Note that subsequent calls will return the same messages if they are
                //       still on the queue, so use some structure defined in an outer block
                //       to identify messages already processed.

            }
            catch (MessageQueueException mqe)
            {
                if (mqe.MessageQueueErrorCode == MessageQueueErrorCode.IOTimeout)
                {
                    // The peek message time-out has expired; there are no messages waiting in the queue
                    continue; // at "while (_bServiceRunning)"
                }
                else
                {
                    ErrorNotification.AppLogError("MSMQ Receive Failed for queue: " + mqs.Name, mqe);
                    break; // from "while (_bServiceRunning)"
                }
            }
            catch (Exception ex)
            {
                ErrorNotification.AppLogError("MSMQ Receive Failed for queue: " + mqs.Name, ex);
                break; // from "while (_bServiceRunning)"
            }
        }

    } // ProcessMessageQueue()

      

0


a source


IMHO you should just turn on queue logging. Then you are guaranteed a copy of all the messages that were submitted to the queue, and that just isn't the case with your difficult attempt to make your own mechanism to log it all.

It is much easier and more reliable to log and delete logged messages on a schedule if you want something more readable than the queue itself (and I certainly would). Then it doesn't matter how fast or not the process works, you only need to receive messages once, and in general this is a much better way to solve the problem.

0


a source







All Articles