Comment puis-je souscrire à une file d'attente MSMQ mais seulement « coup d'oeil » le message en .Net?

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

Question

Nous avons une configuration MSMQ la file d'attente qui reçoit les messages et est traité par une application. Nous aimerions avoir un autre processus abonner à la file d'attente et il suffit de lire le message et le journal contenu est tout.

J'ai ce déjà en place, le problème est qu'il est constamment jeter un oeil à la file d'attente. CPU sur le serveur lorsque cela est en cours d'exécution est d'environ 40%. Les pistes mqsvc.exe à 30% et cela va app à 10%. Je préfère avoir quelque chose qui attend juste un message à venir, get avisée, puis il enregistre sans cesse l'interrogation du serveur.

    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
Était-ce utile?

La solution

A Thread.Sleep (10) entre les itérations PEEK peut vous faire économiser un tas de cycles.

La seule autre option que je peux penser est de construire l'exploitation forestière dans l'application de lecture de file d'attente.

Autres conseils

Avez-vous essayé d'utiliser MSMQEvent.Arrived pour suivre les messages?

  

L'événement Arrivé de l'objet MSMQEvent est déclenché lorsque la méthode de MSMQQueue.EnableNotification d'une instance de l'objet MSMQQueue représentant une file d'attente ouverte a été appelé et un message est trouvé ou arrive à la position applicable dans la file d'attente.

Il n'y a pas d'API qui vous permettra de jeter un regard à chaque message une seule fois.

Le problème est que BeginPeek exécute son rappel immédiatement s'il y a déjà un message sur la file d'attente. Puisque vous ne supprimez pas le message (ce qui est coup d'oeil après tout, pas reçu!), Lorsque votre rappel commence jeter un oeil à nouveau le processus recommence, alors exécute MessageFound presque constamment.

Vos meilleures options pour enregistrer les messages dans l'auteur ou le lecteur. Journalisation travaillera pour de courtes périodes (si vous ne vous préoccupez des messages reçus), mais ne sont pas une solution à long terme:

  

Alors que les frais généraux de performance   la récupération des messages à partir d'une file d'attente   est configuré pour la journalisation est seulement   environ 20% de plus que la récupération   messages sans Journalisation, le vrai   le coût est des problèmes inattendus causés   quand un service est exécuté non vérifiées MSMQ   hors de la mémoire ou de la machine est hors de   espace disque

Cela fonctionne pour moi. Il bloque le fil en attente d'un message. Chaque cycle de boucle vérifie le membre de la classe _bServiceRunning pour voir si le thread doit abandonner.

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

à mon humble avis, vous devez simplement activer la journalisation sur la file d'attente. Ensuite, vous êtes assuré une copie est conservée de tous les messages qui ont été commis à la file d'attente, et que tout est pas le cas avec votre tentative laborous de faire votre propre mécanisme pour se connecter tout.

Beaucoup, beaucoup plus facile et plus fiable consiste à enregistrer et supprimer les messages journalisés sur une base régulière si vous voulez quelque chose de plus facile à lire que la file d'attente elle-même (et je veux certainement que). Ensuite, il ne compte pas vraiment à quelle vitesse ou non le processus fonctionne, il vous suffit d'obtenir les messages une fois, et il est globalement juste une façon beaucoup mieux pour résoudre le problème.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top