¿Cómo me suscribo a una cola MSMQ pero sólo “vistazo” el mensaje en .Net?
-
02-10-2019 - |
Pregunta
Tenemos una configuración de cola de MSMQ que recibe mensajes y es procesada por una aplicación. Nos gustaría tener otro proceso suscribirse a la cola y que acaba de leer el mensaje y ingrese su contenido.
Tengo esto en el lugar ya, el problema es que es constantemente asomando la cola. CPU en el servidor cuando este está en funcionamiento es de alrededor de 40%. Las carreras Mqsvc.exe en 30% y esta aplicación funciona a 10%. Yo prefiero tener algo que sólo espera un mensaje a entrar, para conseguir de notificado de la misma, y ??luego lo registra sin estar constantemente sondeando el servidor.
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
Solución
A Thread.Sleep (10) en entre iteraciones ojeada puede ahorrar un montón de ciclos.
La única otra opción que se me ocurre es la construcción de la tala en la aplicación de lectura de cola.
Otros consejos
¿Ha intentado utilizar MSMQEvent.Arrived para realizar un seguimiento de los mensajes?
El evento Llegado del objeto MSMQEvent se activa cuando el método MSMQQueue.EnableNotification de una instancia del objeto MSMQQueue que representa una cola abierta ha sido llamada y un mensaje se encuentra o llega a la posición de aplicación en la cola.
No hay API que le permitirá vistazo a cada mensaje una sola vez.
El problema es que BeginPeek
ejecuta su devolución de llamada de inmediato si ya hay un mensaje en la cola. Puesto que no se está eliminando el mensaje (esto es peek , después de todo, no recibirá!), Cuando su devolución de llamada empieza asomando de nuevo el proceso comienza de nuevo, por lo que se ejecuta MessageFound
casi constantemente.
Sus mejores opciones son para registrar los mensajes en el escritor o el lector. el diario funcionará por períodos cortos (si sólo se preocupan por los mensajes que se reciben), pero no son una solución a largo plazo:
Mientras que la sobrecarga de rendimiento de la recuperación de mensajes de una cola que está configurado para un diario es solamente aproximadamente un 20% más de recuperación mensajes sin registro en el diario, el real costo es problemas inesperados causados cuando un sin marcar, se ejecuta el servicio de MSMQ sin memoria o la máquina está fuera de espacio en disco
Esto funciona para mí. Bloquea la rosca a la espera de un mensaje. Cada ciclo de bucle comprueba el _bServiceRunning
miembro de la clase para ver si el hilo debe abortar.
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()
En mi humilde opinión que sólo se debe encender en diario en la cola. A continuación, se le garantiza una copia se mantiene de todos los mensajes que se han cometido a la cola, y que simplemente no es el caso con su intento laborous para hacer su propio mecanismo para registrar todo.
Mucho, mucho más fácil y más fiable es para registrar y eliminar los mensajes registrados en diario de forma programada, si quieres algo más fácil de leer que la propia cola (y ciertamente querría eso). Entonces realmente no importa qué tan rápido o no el proceso está funcionando, sólo es necesario para obtener los mensajes de una vez, y es en conjunto es sólo una manera mucho mejor para resolver el problema.