2017-06-09 9 views
1

Sie haben ein seltsames Problem mit vergifteten Nachrichten in einer MSMQ-Warteschlange gemeldet. Wenn eine vergiftete Nachricht erkannt wird, verwende ich den folgenden Code, um die Ausnahme zu behandeln und die Nachricht in die Poison-Warteschlange zu verschieben. Dies schlägt jedoch fehl, weil die Nachricht nicht gefunden wird, obwohl ich die lookupId von der ausgelösten Ausnahme erhalte. Siehe relevanten Code unten.MSMQ-Nachricht wurde nicht in der Warteschlange gefunden

public bool HandleError(Exception error) 
{ 
    var poisonException = error as MsmqPoisonMessageException; 
    if (null == poisonException) return false; 

    var lookupId = poisonException.MessageLookupId; 

    var queuePath = Environment.MachineName + "\\" + ConfigurationManager.AppSettings["QueuePath"]; 
    var poisonQueuePath = Environment.MachineName + "\\" + ConfigurationManager.AppSettings["PoisonQueuePath"]; 

    var orderQueue = new System.Messaging.MessageQueue(queuePath); 
    var poisonMessageQueue = new System.Messaging.MessageQueue(poisonQueuePath); 

    // Use a new transaction scope to remove the message from the main queue and add it to the poison queue. 
    using (var txScope = new TransactionScope(TransactionScopeOption.RequiresNew)) 
    { 
     int retryCount = 0; 
     while (retryCount < 3) 
     { 
      retryCount++; 

      try 
      { 
       // Try to get the poison message using the look up id. This line throws InvalidOperationException 
       var message = orderQueue.ReceiveByLookupId(lookupId); 
       // Send the message to the poison message queue. 
       poisonMessageQueue.Send(message, System.Messaging.MessageQueueTransactionType.Automatic); 

       txScope.Complete(); 

       Logger.Debug("Moved poisoned message with look up id: " + lookupId + " to poison queue: " + ConfigurationManager.AppSettings["PoisonQueuePath"]); 
       break; 
      } 
      catch (InvalidOperationException e) 
      { 
       if (retryCount < 3) 
       { 
        Logger.Debug("Trying to move message to poison queue but message is not available, sleeping for 10 seconds before retrying", e); 
        Thread.Sleep(TimeSpan.FromSeconds(10)); 
       } 
       else 
       { 
        Logger.Debug("Giving up on trying to move the message", e); 
       } 
      } 
     } 
    } 

    Logger.Info("Restarting the service to process rest of the messages in the queue"); 
    WaitCallback restartCallback = new WaitCallback(Start); 
    ThreadPool.QueueUserWorkItem(restartCallback); 

    return true; 
} 

Dieser Code wird im Grunde von der Microsoft-Beispielcode here kopiert.

Der Fehler geworfen ist vom richtigen Typ:

System.ServiceModel.MsmqPoisonMessageException: The transport channel detected a poison message. 

Aber beim Versuch, die Nachricht aus der Warteschlange zu bekommen, erhalte ich:

System.InvalidOperationException: Message requested was not found in the queue specified. 

Mein erster Gedanke war, dass die Warteschlangen nicht haben könnten die richtigen Berechtigungen festgelegt, aber ich habe überprüft, dass der Netzwerkdienstbenutzer alle erforderlichen Rechte zum Lesen und Schreiben von Nachrichten in beiden Warteschlangen hat.

Es ist erwähnenswert, dass dieser Code seit Monaten perfekt in der Produktion funktioniert und in der Vergangenheit viele vergiftete Nachrichten überstanden hat. Jede Eingabe zu dem, was dieses Problem verursacht haben könnte, wird sehr geschätzt.

+0

Wenn dies in prod für einige Zeit gearbeitet hat, wie Sie sagen, ich bei der Konfiguration suchen würde, anstatt Code. Gibt es eine Chance, dass environment.machinename oder appsettings.queuename geändert wurden? eine Art Patch oder falsch konfigurierte Bereitstellung? – GregHNZ

+0

@GregHNZ Danke für Ihre Eingabe. Die Konfiguration war eines der ersten Dinge, die ich überprüft habe, und sowohl die Warteschlangennamen als auch der Computername sind unverändert. Unser Hosting-Anbieter sagt, dass an dem Tag, an dem wir Probleme hatten, keine Installation oder ein Patch stattgefunden hat. – cfj

+0

Erkennen Sie nach dem Auftreten dieses Problems weiterhin eine Fehlermeldung? Wenn nicht, würde das bedeuten, dass die Giftnachricht in der Tat aus der Warteschlange verschwunden ist (zum Beispiel, weil die zu erhaltende Zeit abgelaufen ist). Wenn Sie sie weiterhin erkennen, würde das vielleicht vermuten lassen, dass die LookupId schlecht ist. In beiden Fällen können Sie die LookupId zu den Logger.Debug-Aufrufen innerhalb Ihres catch-Blocks hinzufügen. –

Antwort

1

Dies geschieht, wenn mehr als ein Wiederholungszyklus angegeben wurde. Wenn Ihr maxRetryCycles-Wert größer als Null ist und Ihr retryCycleDelay-Wert größer als 30 Sekunden ist, wird das von Ihnen beschriebene Problem angezeigt. Die Nachricht befindet sich tatsächlich in einer Unterwarteschlange mit dem Namen "retry", da sie die retryCycleDelay zwischen den Zyklen wartet. Wenn Ihr IErrorHandler in der Hauptwarteschlange danach sucht, wird er nicht gefunden. Aus irgendeinem Grund löst WCF die MsmqPoisonMessageException am Ende jedes Wiederholungszyklus, nicht nur einmal am Ende aller Wiederholungszyklen. Das bedeutet, dass Ihr IErrorHandler am Ende jedes Zyklus aufgerufen wird. Es scheint mir wirklich seltsam, aber so ist es.

Ein besserer Ansatz jetzt Tage (wenn Sie garantieren können, dass Ihr Code MSMQ 4.0 haben wird) ist, Ihre receiveErrorHandling von "Fault" in "Move" zu ändern und dann Ihren IErrorHandler loszuwerden. Mit diesem Ansatz werden die Nachrichten für Sie verschoben, nachdem alle Wiederholungen und Wiederholungszyklen abgeschlossen sind. Es wird in eine Unterwarteschlange namens "Gift" verschoben.

Sehen Sie hier für weitere Informationen:

Poison Message Handling in MSMQ 4.0

Verwandte Themen