Tiempo de espera del método MSMQ Receive ()

Mi pregunta original de hace un tiempo es la lectura lenta de la cola de MSMQ , sin embargo, he avanzado de eso y ahora creo que conozco el problema un poco más claro.

Mi código (bueno, en realidad es parte de una biblioteca de código abierto que estoy usando) se ve así:

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

Que utiliza la función Messaging.MessageQueue.Receive y la cola es un MessageQueue. El problema es el siguiente.

La línea de código anterior se llamará con el tiempo de espera especificado (10 segundos). La función Receive(...) es una función de locking, y se supone que debe bloquearse hasta que llegue un mensaje a la cola, momento en el que regresará. Si no se recibe ningún mensaje antes de que se scope el tiempo de espera, volverá al 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(...) , al ver que no hay ningún mensaje en la cola y, por lo tanto, esperar a que llegue un nuevo mensaje. Cuando llega un nuevo mensaje (antes del tiempo de espera) , no está detectando este nuevo mensaje y sigue esperando. El tiempo de espera se alcanza finalmente, momento en el que el código continúa y llama a Receive(...) nuevamente, donde recoge el mensaje y lo procesa.

Ahora, este problema solo ocurre después de varios días / semanas. Puedo hacer que vuelva a funcionar normalmente eliminando y volviendo a crear la cola. Sucede en diferentes ordenadores, y en diferentes colas. Así que parece que algo se está acumulando, hasta cierto punto cuando rompe la capacidad de activación / notificación que usa la función Receive(...) .

He comprobado muchas cosas diferentes, y todo parece normal y no es diferente de una cola que funciona normalmente. Hay un montón de espacio en disco (13gig free) y RAM (alrededor de 350MB libres de 1GB por lo que puedo decir). He comprobado las entradas de registro que aparecen todas igual que 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 notablemente incorrecto de eso.

Estoy usando Windows XP en todas las máquinas y todas tienen el Service Pack 3 instalado. No estoy enviando una gran cantidad de mensajes a las colas, como máximo sería 1 cada 2 segundos, pero en general es mucho menos frecuente que eso. Los mensajes también son pequeños y no se acercan al límite de 4 MB.

Lo único que acabo de notar es que los archivos p0000001.mq y r0000067.mq en C: \ WINDOWS \ system32 \ msmq \ storage son 4,096KB, sin embargo, tienen ese tamaño en otras computadoras que también no están experimentando el problema. El problema no ocurre con todas las colas de la computadora a la vez, ya que puedo volver a crear 1 cola de problemas en la computadora y las otras colas aún experimentan el problema.

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

Actualmente la situación es:

  • ComputerA – 4 colas normal
  • ComputerB – 2 colas experimentando problemas, 1 cola normal
  • ComputerC – 2 colas experimentando problemas
  • ComputerD – 1 cola normal
  • ComputerE – 2 colas normales

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

¿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 manejador a una cola en lugar de, si entiendo lo que está haciendo correctamente, realice un bucle Recibiendo cada 10 segundos. Intenta 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(); } } 

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

Básicamente, MSMQ está utilizando UDP con confirmaciones de dos fases. Después de que se recibe un mensaje, debe ser reconocido. Hasta que se confirme, 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ó a que el Coordinador de transacciones distribuidas no pudo comunicarse entre las máquinas como falta de configuración del cortafuegos – otra vez estábamos usando máquinas virtuales clonadas sin sysprep, lo que hacía que las ID de MSMQ internas no fueran únicas y Hizo que recibiera un mensaje en una máquina y lo recibiera en otra. Finalmente, MSMQ se da cuenta de las cosas, pero lleva bastante tiempo.

Espero que esto ayude.

Prueba esto

Recepción de mensajes públicos (TimeSpan timeout, Cursor cursor)

Función sobrecargada.

Para obtener un cursor para un 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 al principio de la cola. Esto incluye leer mensajes de forma síncrona o asíncrona. No es necesario utilizar los cursores para leer solo el primer mensaje en una cola.

Al leer mensajes dentro de una transacción, Message Queue Server no retrocede el movimiento del cursor si la transacción se cancela. 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 Queue Server mueve el cursor al mensaje A2. Sin embargo, si la transacción se cancela por algún motivo, el mensaje A1 se inserta nuevamente en la cola, pero el cursor sigue apuntando al mensaje A2.

Para cerrar el cursor, llame a Cerrar.

Si quieres usar algo completamente sincrónico y sin evento puedes 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; }