2011-11-15 10 views
9

Tengo esto en una clase llamada "MessageQueueReceive".Recibir MSMQ con transacción - reversión no hacer que el mensaje vuelva a estar disponible

public MessageQueueTransaction BlockingReceive(out Message message) 
{ 
    MessageQueueTransaction tran = null; 
    message = null; 

    tran = new MessageQueueTransaction(); 

    tran.Begin(); 
    try 
    { 
     message = Queue.Receive(new TimeSpan(0, 0, 5), tran); 
    } 
    catch (MessageQueueException ex) 
    { 
     // If the exception was a timeout, then just continue 
     // otherwise re-raise it. 
     if (ex.MessageQueueErrorCode != MessageQueueErrorCode.IOTimeout) 
      throw ex; 
    } 

    return tran; 

} 

Entonces mi bucle de procesamiento tiene esta: - herramienta de panel

while (!Abort) 
{ 
    try 
    { 
     tran = this.Queue.BlockingReceive(out msg); 

     if (msg != null) 
     { 
      // Process message here 

      if (tran != null) 
       tran.Commit(); 
     } 
    } 
    catch (Exception ex) 
    { 
     if (tran != null) 
      tran.Abort(); 

    } 
} 

El control muestra que las colas de mensajes que estoy usando son transaccionales. La cola del diario no está habilitada.

Este código crea la cola: -

private static MessageQueue CreateMessageQueue(string queueName, bool transactional = false) 
{ 
    MessageQueue messageQueue = MessageQueue.Create(queueName, transactional); 
    messageQueue.SetPermissions("Administrators", MessageQueueAccessRights.FullControl, 
      AccessControlEntryType.Allow); 
    return messageQueue; 
} 

El parámetro transaccional se establece como "verdadero" en que se requiera.

Lo que encuentro es que cuando ocurre una excepción durante el procesamiento del mensaje, se llama a tran.Abort, pero en ese punto esperaría que el mensaje se devuelva a la cola. Sin embargo, esto no está sucediendo y los mensajes se pierden.

¿Me falta algo obvio? ¿Alguien puede ver lo que estoy haciendo mal?

+0

¿La cola que está recibiendo en local para el servicio de escucha? –

+0

Sí, los procesos de envío y recepción y las colas están todos en la misma casilla. Son colas privadas. También tengo el mismo código ejecutándose en algunos cuadros diferentes, y veo el mismo problema en todos.Eso sugiere que está relacionado con este código en lugar de algo peculiar sobre la máquina. – JohnCC

+0

Pregunta obvia, supongo. ¿Estás seguro de que está llegando a la excepción con el aborto? ¿Es posible que se haya lanzado una excepción en el código de manejo de mensajes que se ha capturado y luego se ha descartado para que nunca se propague a usted el manejador de excepciones con el aborto en él? –

Respuesta

5

Gracias por todos los comentarios. Reorganicé mi código como sugirió Russell McClure, e intenté crear casos de prueba simples pero no pude reproducir el problema.

Al final, el problema no era en absoluto donde estaba mirando (¿con qué frecuencia sucede eso?).

En mi canalización, tenía un comprobador de mensajes duplicados. Los "mensajes" que trata mi sistema provienen de dispositivos remotos en una WAN, y ocasionalmente los mensajes en el cable están duplicados.

Cuando se extrae un mensaje del MSMQ, pasa a través del comprobador duplicado el escritor de la base de datos. Si el escritor de la base de datos falló, el duplicado seleccionado no eliminó el hash de su tabla. Cuando el proceso intente repetir el bucle, recibirá el mismo mensaje de la cola porque la transacción MSMQ se ha retrotraído cuando el escritor de la base de datos ha fallado. Sin embargo, en el segundo intento, el inspector duplicado detectaría que había visto el mensaje anteriormente y se lo tragaría en silencio.

La solución consistía en hacer que el inspector duplicado detectara la excepción proveniente del siguiente eslabón de la cadena, y revertir cualquier cosa que hubiera hecho también.

1

Su cola debe crearse como una cola transaccional para obtener lo que desea.

enter image description here

EDIT:

Bueno, si la cola es transaccional entonces que apunta al hecho de que están mal manejo de su transacción, aunque no puedo ver específicamente cómo está sucediendo. Cambiaría su método BlockingReceive para devolver el mensaje. Movería la creación del MessageQueueTransaction al método externo. Su código será mucho más fácil de mantener si tiene las llamadas al método Begin, Commit and Abort en el mismo método.

+0

¡Hola! Las colas definitivamente se crean como colas transaccionales. Si miro las propiedades de la cola en Computer Management-> Services and Applications -> Message Queuing, se muestra como transaccional. – JohnCC

Cuestiones relacionadas