كيف يمكنني الاشتراك في قائمة انتظار MSMQ ولكن فقط "نظرة خاطفة على الرسالة في .NET؟

StackOverflow https://stackoverflow.com/questions/2760485

سؤال

لدينا إعداد قائمة انتظار MSMQ يتلقى الرسائل ويتم معالجته بواسطة تطبيق. نرغب في الاشتراك في عملية أخرى في قائمة الانتظار ونقرأ الرسالة وتسجيل محتوياتها.

لدي هذا في مكانه بالفعل ، المشكلة هي أنها تطل على قائمة الانتظار باستمرار. وحدة المعالجة المركزية على الخادم عند تشغيل هذا حوالي 40 ٪. يعمل MQSVC.Exe بنسبة 30 ٪ ويعمل هذا التطبيق بنسبة 10 ٪. أفضل أن أحصل على شيء ينتظر أن تأتي رسالة ، وإخطارها بها ، ثم يقوم بتسجيلها دون استقصاء الخادم باستمرار.

    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's write it out
                log.write(oMessage)
            End If

        objQueue.BeginPeek()
    End Sub
هل كانت مفيدة؟

المحلول

قد يوفر لك Thread.sleep (10) بين تكرارات نظرة خاطفة مجموعة من الدورات.

الخيار الآخر الوحيد الذي يمكنني التفكير فيه هو إنشاء تسجيل الدخول إلى تطبيق قراءة قائمة الانتظار.

نصائح أخرى

هل حاولت استخدام MSMQEVENT.ARRIVER لتتبع الرسائل؟

يتم إطلاق الحدث الذي وصل إلى كائن MSMQEvent عند استدعاء طريقة MSMQQueue.EnableNotification لمثيل كائن MSMQQueue الذي يمثل قائمة انتظار مفتوحة وتم العثور على رسالة أو تصل إلى الموضع المعمول به في قائمة الانتظار.

لا يوجد واجهة برمجة تطبيقات تتيح لك نظرة خاطفة على كل رسالة مرة واحدة فقط.

المشكلة هي BeginPeek ينفذ رد الاتصال على الفور إذا كانت هناك بالفعل رسالة في قائمة الانتظار. نظرًا لأنك لا تزيل الرسالة (هذه هي نظرة خاطفة بعد كل شيء ، لا تستقبل!) ، عندما يبدأ رد الاتصال الخاص بك في النظر مرة أخرى ، تبدأ العملية من جديد ، لذلك MessageFound يدير باستمرار تقريبا.

أفضل خياراتك هي تسجيل الرسائل في الكاتب أو القارئ. اليومية ستعمل لفترات قصيرة (إذا كنت تهتم فقط بالرسائل التي يتم استلامها) ، ولكنها ليست حلاً طويل الأجل:

في حين أن الأداء النفقات العامة لاسترداد الرسائل من قائمة انتظار تم تكوينه في اليومية لا يزيد سوى بنسبة 20 ٪ فقط من استرداد الرسائل دون إجراء دفتر اليومية ، فإن التكلفة الحقيقية هي مشاكل غير متوقعة ناتجة عندما تنفد خدمة MSMQ غير المرصودة من الذاكرة أو الجهاز خارج القرص الفضاء

هذا يعمل بالنسبة لي. يحظر الموضوع أثناء انتظار رسالة. كل دورة حلقة تتحقق من عضو الفصل _bServiceRunning لمعرفة ما إذا كان يجب أن يعمل الخيط.

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

IMHO يجب عليك فقط تشغيل اليومية في قائمة الانتظار. بعد ذلك ، يتم إبقاء نسخة من جميع الرسائل التي تم التزامها بقائمة الانتظار ، وهذا ليس هو الحال في محاولتك المتطورة لجعل آليتك الخاصة لتسجيل كل شيء.

أسهل بكثير وأكثر موثوقية هو تسجيل وإزالة الرسائل المجلة على أساس مجدول إذا كنت تريد شيئًا أكثر سهولة من القراءة من قائمة الانتظار نفسها (وأنا بالتأكيد أريد ذلك). بعد ذلك ، لا يهم حقًا مدى السرعة أو لا تعمل العملية ، فأنت بحاجة فقط إلى الحصول على الرسائل مرة واحدة ، وهي بشكل عام مجرد طريقة أفضل لحل المشكلة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top