2009-11-25 25 views
12

Mi pregunta original de hace un tiempo es MSMQ Slow Queue Reading, sin embargo, he avanzado desde eso y ahora creo que sé que el problema es un poco más claro.MSMQ Receive() método de tiempo de espera

Mi código (bueno en realidad parte de una biblioteca de código abierto que estoy usando) tiene el siguiente aspecto:

queue.Receive(TimeSpan.FromSeconds(10), MessageQueueTransactionType.Automatic); 

que está utilizando la función Messaging.MessageQueue.Receive y la cola es una MessageQueue. El problema es el siguiente.

Se invocará la línea de código anterior con el tiempo de espera especificado (10 segundos). La función Receive(...) es una función de bloqueo, y se supone que debe bloquear hasta que llegue un mensaje en la cola y en ese momento volverá. Si no se recibe ningún mensaje antes de que se agote el tiempo de espera, volverá en el tiempo de espera. Si un mensaje está en la cola cuando se llama a la función, devolverá ese mensaje inmediatamente.

Sin embargo, lo que está sucediendo es que se está llamando a la función Receive(...), viendo que no hay ningún mensaje en la cola y esperando que entre un nuevo mensaje. Cuando ingresa un nuevo mensaje (antes del tiempo de espera), no está detectando este nuevo mensaje y continúa esperando. El tiempo de espera finalmente se alcanza, en cuyo punto el código continúa y llama al Receive(...) nuevamente, donde recoge el mensaje y lo procesa.

Ahora, este problema solo ocurre después de un número de días/semanas. Puedo hacer que funcione normalmente de nuevo eliminando & recreando la cola. Sucede en diferentes computadoras y diferentes colas. Por lo tanto, parece que algo se está acumulando, hasta cierto punto cuando se rompe la capacidad de activación/notificación que utiliza la función Receive(...).

He comprobado muchas cosas diferentes, y todo parece normal & no es diferente de una cola que funciona normalmente. Hay un montón de espacio en disco (13 gig gratis) y RAM (alrededor de 350 MB sin 1 GB de lo que puedo decir). He revisado las entradas de registro, que parecen todas iguales a las otras colas, y el monitor de rendimiento no muestra nada fuera de lo normal. También he ejecutado la herramienta TMQ y no puedo ver nada notoriamente erróneo a partir de eso.

Estoy usando Windows XP en todas las máquinas y todas tienen Service Pack 3 instalado. No estoy enviando una gran cantidad de mensajes a las colas, a lo sumo sería 1 cada 2 segundos, pero en general mucho menos frecuentes que eso. Los mensajes son pequeños también y no están cerca del límite de 4MB.

Lo único que acabo de notar es que los archivos p0000001.mq y r0000067.mq en C: \ WINDOWS \ system32 \ msmq \ storage son ambos 4.096KB pero también tienen ese tamaño en otras computadoras que no están experimentando actualmente el problema. El problema no le ocurre a todas las colas en la computadora a la vez, ya que puedo recrear 1 cola de problemas en la computadora y las otras colas todavía experimentan el problema.

No tengo mucha experiencia con MSMQ así que si publica cosas posibles para verificar, puede explicar cómo verificarlas o dónde puedo encontrar más detalles de lo que está hablando.

Actualmente la situación es:

  • EquipoA - 4 colas normales
  • ComputerB - 2 colas que experimentan problema, 1 cola normal de
  • ComputerC - 2 colas que experimentan problema
  • SistemaD - 1 cola normal de
  • ComputerE - 2 colas normal

Así que tengo una gran cantidad de computadoras/colas para comparar y contrastar.

+0

Lo que utiliza la biblioteca de código abierto? ¿Es un problema conocido de su parte? –

+0

Es NServiceBus (www.nservicebus.com). No parece que nadie más experimente el problema (al menos nadie en la lista de correo). Mi explicación de cómo funciona se basa en cómo lo describe el propietario. "Un subproceso de NServiceBus busca en la cola un mensaje después de que termina de procesar el mensaje anterior (o al inicio). El comportamiento habitual de un vistazo es bloquear hasta que llega un mensaje, pero NServiceBus limita esto con un tiempo de espera para permitir el apagado correcto en cualquier punto del tiempo ". Y la línea de código que pegué es el mencionado 'vistazo'. – mike

+1

Bueno, no soy un experto en el campo, pero estoy mirando la cola. Espero que el segundo parámetro no sea el más adecuado en su caso, tal vez cambiando a "MessageQueueTransactionType.None" (si no necesita la función de transacción) seria mejor. La segunda forma de eludir esto (en mi opinión) sería mover la función de tiempo de espera fuera de esta llamada, lo que significa que en esta llamada solo espere 0 segundos y espere en otro lugar de su código. Entiendo que estas opciones pueden no ser ideales ya que es posible que deba cambiar el contenido de la biblioteca o su código. buena suerte –

Respuesta

0

Trate recibir este

mensaje público (tiempo de espera TimeSpan, el cursor Cursor)

función sobrecargada.

Para obtener un cursor para una MessageQueue, llame al método CreateCursor para esa cola.

Un Cursor se usa con métodos como Peek (TimeSpan, Cursor, PeekAction) y Receive (TimeSpan, Cursor) cuando necesita leer mensajes que no están en la parte delantera de la cola. Esto incluye leer mensajes de forma síncrona o asíncrona. Los cursores no necesitan ser utilizados para leer solo el primer mensaje en una cola.

Al leer mensajes dentro de una transacción, Message Queue Server no retrotrae el movimiento del cursor si se cancela la transacción. Por ejemplo, supongamos que hay una cola con dos mensajes, A1 y A2. Si elimina el mensaje A1 mientras está en una transacción, Message Queuing mueve el cursor al mensaje A2. Sin embargo, si la transacción se cancela por algún motivo, el mensaje A1 se inserta de nuevo en la cola, pero el cursor permanece apuntando al mensaje A2.

Para cerrar el cursor, llame a Cerrar.

8

¿Alguna razón particular por la que no está utilizando un controlador de eventos para escuchar las colas? La biblioteca System.Messaging le permite adjuntar un controlador a una cola en lugar de, si entiendo lo que está haciendo correctamente, el bucle de Recibir cada 10 segundos. Pruebe algo como esto:

class MSMQListener 
{ 
    public void StartListening(string queuePath) 
    { 
     MessageQueue msQueue = new MessageQueue(queuePath); 
     msQueue.ReceiveCompleted += QueueMessageReceived; 
     msQueue.BeginReceive(); 
    } 

    private void QueueMessageReceived(object source, ReceiveCompletedEventArgs args) 
    { 
     MessageQueue msQueue = (MessageQueue)source; 

     //once a message is received, stop receiving 
     Message msMessage = null; 
     msMessage = msQueue.EndReceive(args.AsyncResult); 

     //do something with the message 

     //begin receiving again 
     msQueue.BeginReceive(); 
    } 
} 
+0

La razón principal es que no puede recibir de forma asíncrona desde una cola transaccional. Esta restricción se puede rastrear hasta llegar a [la API nativa] (https://msdn.microsoft.com/en-us/library/ms699825 (v = vs.85) .aspx). – acelent

3

También estamos utilizando NServiceBus y tuvimos un problema similar dentro de nuestra red.

Básicamente MSMQ usa UDP con confirmaciones de dos fases. Después de recibir un mensaje, debe ser reconocido. Hasta que se reconozca, no se puede recibir en el lado del cliente ya que la transacción de recepción no se ha finalizado.

Esto fue causado por diferentes cosas en diferentes momentos para nosotros: - una vez que esto se debió al Coordinador de transacciones distribuidas incapaces de comunicarse entre máquinas como una mala configuración del cortafuegos - otra vez estábamos usando máquinas virtuales clonadas sin sysprep que hizo interna ID de MSMQ no únicos e hicieron que recibiera un mensaje en una máquina y acuse recibo en otra. Finalmente, MSMQ resuelve las cosas, pero lleva bastante tiempo.

Espero que esto ayude.

0

Si desea utilizar algo completamente sincrónica y sin evento puede probar este método

public object Receive(string path, int millisecondsTimeout) 
{ 
    var mq = new System.Messaging.MessageQueue(path); 
    var asyncResult = mq.BeginReceive(); 
    var handles = new System.Threading.WaitHandle[] { asyncResult.AsyncWaitHandle }; 
    var index = System.Threading.WaitHandle.WaitAny(handles, millisecondsTimeout); 
    if (index == 258) // Timeout 
    { 
     mq.Close(); 
     return null; 
    } 
    var result = mq.EndReceive(asyncResult); 
    return result; 
} 
Cuestiones relacionadas