Come faccio a iscrivermi a una coda MSMQ, ma solo “sbirciare” il messaggio in Net?
-
02-10-2019 - |
Domanda
Abbiamo una configurazione MSMQ coda che riceve messaggi e viene elaborato da un'applicazione. Ci piacerebbe avere un altro processo iscriviti alla coda e basta leggere il messaggio e la sua registrazione di contenuti.
Ho questo posto già, il problema è che è costantemente sbirciando la coda. CPU sul server quando questo è in esecuzione è di circa il 40%. Le piste Mqsvc.exe al 30% e questa applicazione funziona a 10%. Avrei preferito qualcosa che solo attende un messaggio di entrare, ottenere di notificato di esso, e quindi i registri senza costantemente il polling del server.
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
Soluzione
A Thread.Sleep (10) tra iterazioni peek può risparmiare un sacco di cicli.
L'unica altra opzione mi viene in mente è quello di costruire la registrazione in applicazione di lettura coda.
Altri suggerimenti
Hai provato a usare MSMQEvent.Arrived per tenere traccia dei messaggi?
L'evento Arrivato dell'oggetto MSMQEvent è sparato quando il metodo MSMQQueue.EnableNotification di un'istanza dell'oggetto MSMQQueue che rappresenta una coda aperta è stata chiamata e un messaggio viene trovato o arriva alla posizione di applicabile nella coda.
Non c'è API che vi permetterà di sbirciare ogni messaggio una sola volta.
Il problema è che BeginPeek
esegue la sua richiamata immediatamente se c'è già un messaggio sulla coda. Dal momento che non sta rimuovendo il messaggio (questo è peek , dopo tutto, non ricevono!), Quando il callback inizia capolino di nuovo il processo ricomincia, quindi corre MessageFound
quasi costantemente.
I tuoi migliori opzioni sono per registrare i messaggi nella scrittore o il lettore. diario lavorerà per brevi periodi (se vi interessa soltanto i messaggi ricevuti), ma non sono una soluzione a lungo termine:
Mentre il sovraccarico delle prestazioni di il recupero dei messaggi da una coda che è configurato per il journaling è solo circa il 20% in più rispetto recupero messaggi senza journal, il vero costo è di problemi imprevisti causati quando un incontrollato eseguito il servizio MSMQ la memoria o la macchina è fuori spazio su disco
Questo funziona per me. Si blocca il filo, mentre in attesa di un messaggio. Ogni controlli a ciclo ciclo del _bServiceRunning
membro della classe per vedere se il filo deve interrompere.
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 si dovrebbe basta accendere nel diario sulla coda. Poi si sono garantiti una copia è conservata di tutti i messaggi che sono stati commessi alla coda, e che proprio non è il caso con il tuo tentativo laborous per rendere il proprio meccanismo per registrare tutto.
Molto, molto più semplice e più affidabile è quello di accedere e rimuovere i messaggi inseriti nel journal in modo pianificato, se volete qualcosa di più facilmente leggibile rispetto alla coda stessa (e certamente vorrebbe che). Poi in realtà non importa quanto velocemente o no il processo sta funzionando, è sufficiente per ottenere i messaggi una volta, ed è nel complesso solo un modo molto migliore per risolvere il problema.