2012-04-26 10 views
9

Tenemos un servicio que recibe mensajes de n colas de mensajes. Sin embargo, si se reinicia el servicio Message Queue Server, el servicio de recuperación de mensajes deja de recibir mensajes incluso después de que el servicio Message Queue Server se haya reiniciado correctamente.El servicio no recibe mensajes después de que se reinició el servicio Message Queue Server

He intentado atrapar específicamente la MessageQueueException que se lanza en el servicio de recuperación de mensajes e invoco nuevamente el método BeginReceive de la cola. Sin embargo, en los 2 segundos aproximadamente que tarda el servicio de Message Queue Server en reiniciarse, obtengo alrededor de 1875 instancias de la excepción y luego el servicio deja de funcionar cuando se lanza otra MessageQueueException en nuestro método StartListening.

¿Hay alguna manera elegante de recuperar desde el reinicio del servicio Message Queue Server?

private void OnReceiveCompleted(object sender, ReceiveCompletedEventArgs e) 
    { 
     MessageQueue queue = (MessageQueue)sender; 

     try 
     { 
      Message message = queue.EndReceive(e.AsyncResult); 

      this.StartListening(queue); 

      if (this.MessageReceived != null) 
       this.MessageReceived(this, new MessageReceivedEventArgs(message)); 
     } 
     catch (MessageQueueException) 
     { 
      LogUtility.LogError(String.Format(CultureInfo.InvariantCulture, StringResource.LogMessage_QueueManager_MessageQueueException, queue.MachineName, queue.QueueName, queue.Path)); 
      this.StartListening(queue); 
     }    
    } 

    public void StartListening(MessageQueue queue) 
    { 
     queue.BeginReceive(); 
    } 

Necesito ocuparme de la cuestión del lazo infinito que esto causa y limpiarlo un poco, pero se entiende la idea.

Cuando se produce la excepción MessageQueueException, invoque el método RecoverQueue.

private void RecoverQueue(MessageQueue queue) 
    {    
     string queuePath  = queue.Path; 
     bool queueRecovered = false; 

     while (!queueRecovered) 
     { 
      try 
      { 
       this.StopListening(queue); 
       queue.Close(); 
       queue.Dispose(); 

       Thread.Sleep(2000); 

       MessageQueue newQueue = this.CreateQueue(queuePath); 

       newQueue.ReceiveCompleted += new ReceiveCompletedEventHandler(this.OnReceiveCompleted); 

       this.StartListening(newQueue); 

       LogUtility.LogInformation(String.Format(CultureInfo.InvariantCulture, "Message queue {0} recovered successfully.", newQueue.QueueName)); 

       queueRecovered = true; 
      } 
      catch (Exception ex) 
      { 
       LogUtility.LogError(String.Format(CultureInfo.InvariantCulture, "The following error occurred while trying to recover queue: {0} error: {1}", queue.QueueName, ex.Message));     
      } 
     }   
    } 

    public void StopListening(MessageQueue queue) 
    { 
     queue.ReceiveCompleted -= new ReceiveCompletedEventHandler(this.OnReceiveCompleted);    
    } 
+0

Publicado el código del método RecoverQueue – chad

Respuesta

8

Al recibir la excepción de que es el resultado de la reanudación del servicio, tiene que liberar el viejo MessageQueue, es decir Unwiring su evento ReceiveCompleted, disponiendo el MessageQueue, etc A continuación, crear una nueva instancia de la MessageQueue y el gancho hasta el evento ReceiveCompleted nuevamente en la nueva instancia MessageQueue.

Alternativamente, puede usar un método de sondeo que crea una nueva instancia en un intervalo determinado, las llamadas MessageQueue.Receive(TimeSpan), esperarán un mensaje entrante o hasta que se agote el tiempo de espera. En ese caso, maneja el mensaje y destruye la instancia MessageQueue y comienza la iteración nuevamente.

Al recrear el MessageQueue cada vez, garantiza una recuperación integrada. Además, la sobrecarga de crear MessageQueue es mínima debido al almacenamiento en caché interno de la cola subyacente.

Pseudocódigo ...

while (!notDone)// or use a timer or periodic task of some sort... 
{ 
    try 
    { 
     using (MessageQueue queue = new MessageQueue(queuePath)) 
     { 
      Message message = queue.Receive(TimeSpan.FromMilliseconds(500)); 

      // process message 
     } 
    } 
    catch (MessageQueueException ex) 
    { 
     // handle exceptions 
    } 
} 
+1

bien, por lo que está básicamente diciendo: "Utilizar una nueva cola cada vez." –

+0

@Bob Horn - Sí. Debido a que la sobrecarga es baja debido al almacenamiento en caché interno, hace que sea más fácil manejar los problemas donde se reinició el servicio MSMQ o de lo contrario deja de responder. – Jim

Cuestiones relacionadas