2012-04-26 124 views
9

我們有一個從n個消息隊列接收消息的服務。但是,如果重新啓動消息隊列服務,則即使消息隊列服務已成功重新啓動,消息檢索服務也會停止接收消息。消息隊列服務重新啓動後服務沒有收到消息

我試圖專門捕獲消息檢索服務中引發的MessageQueueException,並再次調用隊列的BeginReceive方法。但是,在2秒左右的時間內,消息隊列服務纔會重新啓動,我得到大約1875個異常實例,然後在我們的StartListening方法中引發另一個MessageQueueException時服務停止運行。

有沒有一個優雅的方式來從消息隊列服務重新啓動恢復?

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(); 
    } 

我需要處理這個問題導致的無限循環問題,並清理它一下,但你明白了。

發生MessageQueueException時,調用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

發佈的RecoverQueue方法的代碼 – chad 2012-04-26 18:30:00

回答

8

一旦接收到異常是服務重新啓動的結果,你要釋放舊MessageQueue,即您解除wire事件ReceiveCompleted,處置的MessageQueue等,然後創建MessageQueue和掛鉤的新實例在新的MessageQueue實例上再次達到ReceiveCompleted事件。

或者,也可以使用在一定的時間間隔創建一個新的實例的輪詢方法,調用MessageQueue.Receive(TimeSpan),將等待一個傳入消息或直到超時發生。在這種情況下,您處理消息並銷燬實例並再次開始迭代。

通過每次重新創建MessageQueue,確保內置恢復。此外,創建MessageQueue的開銷由於底層隊列的內部緩存而很小。

僞代碼...

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

好了,所以你基本上只是說:「使用新的隊列每次。」 – 2012-04-26 18:40:50

+0

@Bob Horn - 是的。由於內部緩存的開銷較低,因此可以更輕鬆地處理MSMQ服務重新啓動或無法響應的問題。 – Jim 2012-04-26 18:55:05