Behandlung nicht verarbeitbarer Nachrichten

Eine nicht verarbeitbare Nachricht ist eine Nachricht, die auch nach der maximalen Anzahl von Zustellversuchen nicht an die Anwendung ausgeliefert werden konnte. Diese Situation kann auftreten, wenn eine warteschlangenbasierte Anwendung aufgrund der Fehler keine Nachricht verarbeiten kann. Um Zuverlässigkeitsforderungen zu erfüllen, empfängt eine in der Warteschlange stehende Anwendung Nachrichten unter einer Transaktion. Beim Abbrechen der Transaktion, in der eine in der Warteschlange stehende Nachricht empfangen wurde, bleibt die Nachricht in der Warteschlange und wird dann unter einer neuen Transaktion wiederholt. Wenn das Problem, das zum Abbrechen der Transaktion geführt hat, nicht korrigiert wird, kann die empfangende Anwendung in einer Schleife hängen bleiben, in der sie dieselbe Nachricht immer wieder empfängt und abbricht, bis die maximale Anzahl der Zustellversuche überschritten ist. Auf diese Weise entsteht eine nicht verarbeitbare Nachricht.

Eine Nachricht kann aus vielen Gründen zu einer nicht verarbeitbaren Nachrichten werden. Die häufigsten Ursachen sind anwendungsspezifisch. Wenn beispielsweise eine Anwendung eine Nachricht aus einer Warteschlange liest und dann Datenbankprozesse durchführt, kann es vorkommen, dass von der Anwendung keine Sperre für die Datenbank bewirkt werden kann. Dies führt dann dazu, dass sie die Transaktion abbricht. Da die Datenbanktransaktion abgebrochen wurde, verbleibt die Nachricht in der Warteschlange, wodurch die Nachricht von der Anwendung ein zweites Mal gelesen und ein neuer Versuch gestartet wird, eine Sperrung der Datenbank zu bewirken. Nachrichten können auch nicht verarbeitbar werden, wenn sie ungültige Informationen enthalten. So enthält z. B. eine Bestellung möglicherweise eine ungültige Kundennummer. In diesen Fällen kann die Anwendung die Transaktion freiwillig abbrechen und die Nachricht zwingen, eine nicht verarbeitbare Nachricht zu werden.

Bei seltenen Gelegenheiten können Nachrichten nicht zur Anwendung weitergeleitet werden. Die WCF-Schicht (Windows Communication Foundation) kann ein Problem mit der Nachricht feststellen, beispielsweise wenn die Nachricht den falschen Frame, ungültige Nachrichtenanmeldeinformationen im Anhang oder einen ungültigen Aktionsheader aufweist. In diesen Fällen empfängt die Anwendung die Nachricht niemals; trotzdem kann die Nachricht noch zu einer nicht verarbeitbaren Nachricht werden, die manuell verarbeitet werden kann.

Behandeln von nicht verarbeitbaren Nachrichten

In WCF bietet die Behandlung nicht verarbeitbarer Nachrichten einen Mechanismus, mit dem eine empfangende Anwendung mit Nachrichten umgehen kann, die nicht zur Anwendung weitergeleitet werden können, oder mit Nachrichten, die zwar zur Anwendung weitergeleitet werden, deren Verarbeitung jedoch aus anwendungsspezifischen Gründen fehlschlägt. Konfigurieren Sie die Behandlung nicht verarbeitbarer Nachrichten mit den folgenden Eigenschaften in jeder der verfügbaren, in der Warteschlange stehenden Bindungen:

  • ReceiveRetryCount. Ein Ganzzahlwert, die die maximale Anzahl der Neuversuche für den Versand einer Nachricht von der Anwendungswarteschlange zu der Anwendung angibt. Der Standardwert ist 5. Dieser Wert ist in Fällen ausreichend, in denen eine sofortige Wiederholung das Problem behebt, beispielsweise wenn ein temporärer Deadlock für eine Datenbank vorliegt.

  • MaxRetryCycles. Ein Ganzzahlwert, der die maximale Anzahl der Wiederholungszyklen angibt. Ein Wiederholungszyklus umfasst die Übertragung einer Nachricht von der Anwendungswarteschlange zur untergeordneten Wiederholungswarteschlange und – nach einer konfigurierbaren Verzögerung – die Rückübertragung der Nachricht aus der untergeordneten Wiederholungswarteschlange zur Anwendungswarteschlange, um einen erneuten Zustellversuch zu unternehmen. Der Standardwert ist 2. Unter Windows Vista wird die Nachricht maximal (ReceiveRetryCount +1) * (MaxRetryCycles + 1) Mal versucht. MaxRetryCycles wird unter Windows Server 2003 und Windows XP ignoriert.

  • RetryCycleDelay. Die Verzögerungszeit für Wiederholungszyklen. Der Standardwert ist 30 Minuten. MaxRetryCycles und RetryCycleDelay bieten gemeinsam einen Mechanismus zur Behandlung des Problems, wenn eine Wiederholung nach einer periodischen Verzögerung das Problem behebt. Damit wird z. B. ein gesperrtes Rowset bei einem in SQL Server anstehenden Transaktionscommit behandelt.

  • ReceiveErrorHandling. Eine Enumeration, die angibt, welche Aktion für eine Nachricht erfolgen soll, deren Zustellung auch nach der maximalen Anzahl von Wiederholungen fehlgeschlagen ist. Die Werte können „Fehler“, „Ablegen“, „Ablehnen“ und „Verschieben“ sein. Die Standardoption ist "Fehler".

  • Fehler. Diese Option sendet einen Fehler an den Listener, der bewirkt hat, dass der ServiceHost fehlerhaft agiert. Die Nachricht muss durch einen externen Mechanismus aus der Anwendungswarteschlange entfernt werden, bevor die Anwendung mit der Verarbeitung von Nachrichten aus der Warteschlange fortfahren kann.

  • Ablage. Diese Option legt die nicht verarbeitbare Nachricht ab, und die Nachricht wird der Anwendung nie zugestellt. Wenn die Eigenschaft TimeToLive der Nachricht zu diesem Zeitpunkt bereits abgelaufen ist, kann die Nachricht in der Warteschlange für unzustellbare Nachrichten des Absenders angezeigt werden. Andernfalls wird die Nachricht nirgendwo angezeigt. Diese Option gibt an, dass vom Benutzer keine Aktion für den Fall angegeben wurde, dass die Nachricht verloren geht.

  • Ablehnen. Diese Option ist nur unter Windows Vista verfügbar. Damit wird das Message Queuing (MSMQ) angewiesen, eine negative Bestätigung mit dem Hinweis, dass die Anwendung die Nachricht nicht empfangen kann, an den sendenden Warteschlangen-Manager zu senden. Die Nachricht wird in die Warteschlange für unzustellbare Nachrichten des sendenden Warteschlangen-Managers eingefügt.

  • Verschieben. Diese Option ist nur unter Windows Vista verfügbar. Damit wird die nicht verarbeitbare Nachricht in eine Warteschlange für potenziell schädliche Nachrichten verschoben, sodass sie später durch eine Anwendung zur Behandlung nicht verarbeitbarer Nachrichten verarbeitet werden kann. Die Warteschlange für potenziell schädliche Nachrichten ist eine untergeordnete Warteschlange der Anwendungswarteschlange. Eine Anwendung für nicht verarbeitbare Nachrichten kann ein WCF-Dienst sein, der Nachrichten aus der Warteschlange für nicht verarbeitbare Nachrichten liest. Die Warteschlange für potenziell schädliche Nachrichten ist eine untergeordnete Warteschlange der Anwendungswarteschlange und kann als net.msmq://<machine-name>/applicationQueue;poison adressiert werden, wobei machine-name der Name des Computers ist, auf dem sich die Warteschlange befindet, applicationQueue gibt den Namen der anwendungsspezifischen Warteschlange an.

Im Folgenden ist die maximale Anzahl von für eine Nachricht durchgeführten Übermittlungsversuchen dargestellt:

  • ((ReceiveRetryCount+1) * (MaxRetryCycles + 1)) unter Windows Vista.

  • (ReceiveRetryCount + 1) unter Windows Server 2003 und Windows XP.

Hinweis

Für eine Nachricht, die erfolgreich zugestellt wird, werden keine Wiederholungen durchgeführt.

Zur Nachverfolgung, wie oft das Lesen einer Nachricht versucht wurde, verfügt Windows Vista über eine dauerhafte Nachrichteneigenschaft, die die Anzahl der Abbrüche zählt, und über eine Eigenschaft zum Zählen von Verschiebungen, die zählt, wie oft die Nachricht zwischen der Anwendungswarteschlange und den untergeordneten Warteschlangen verschoben wurde. Der WCF-Kanal verwendet diese Eigenschaften zur Berechnung der Empfangswiederholungsanzahl und der Wiederholungszyklusanzahl. Unter Windows Server 2003 und Windows XP wird die Abbruchanzahl vom WCF-Kanal im Arbeitsspeicher beibehalten und zurückgesetzt, wenn die Anwendung nicht erfolgreich ist. Außerdem kann der WCF-Kanal die Abbruchanzahl für bis zu 256 Nachrichten zu jedem beliebigen Zeitpunkt im Arbeitsspeicher führen. Wenn eine 257. Nachricht gelesen wird, dann wird die Abbruchanzahl der ältesten Nachricht zurückgesetzt.

Die Abbruchanzahl- und Verschiebungsanzahleigenschaften stehen dem Dienstvorgang durch den Vorgangskontext zur Verfügung. Im folgenden Codebeispiel wird der Zugriff darauf veranschaulicht.

MsmqMessageProperty mqProp = OperationContext.Current.IncomingMessageProperties[MsmqMessageProperty.Name] as MsmqMessageProperty;
Console.WriteLine("Abort count: {0} ", mqProp.AbortCount);
Console.WriteLine("Move count: {0} ", mqProp.MoveCount);
// code to submit purchase order ...

WCF stellt zwei in der Warteschlange stehende Standardbindungen bereit:

  • NetMsmqBinding. Eine .NET Framework-Bindung, die für die Durchführung der warteschlangenbasierten Kommunikation mit anderen WCF-Endpunkten geeignet ist.

  • MsmqIntegrationBinding. Eine Bindung, die zur Kommunikation mit vorhandenen Message Queuing-Anwendungen geeignet ist.

Hinweis

Sie können Eigenschaften in diesen Bindungen auf der Grundlage der Anforderungen Ihres WCF-Diensts ändern. Der gesamte Mechanismus zur Behandlung nicht verarbeitbarer Nachrichten ist zur empfangenden Anwendung lokal. Der Prozess ist für die sendende Anwendung unsichtbar, es sei denn, die empfangende Anwendung beendet den Vorgang und sendet eine negative Bestätigung an den Absender zurück. In diesem Fall wird die Nachricht in die Warteschlange für unzustellbare Nachrichten des Absenders verschoben.

Empfohlene Vorgehensweise: Behandlung MsmqPoisonMessageException

Wenn der Dienst feststellt, dass eine Nachricht nicht verarbeitbar ist, löst der Warteschlangentransport eine MsmqPoisonMessageException aus, die die LookupId der nicht verarbeitbaren Nachricht enthält.

Eine empfangende Anwendung kann die IErrorHandler-Schnittstelle implementieren, um alle Fehler zu behandeln, die die Anwendung erfordert. Weitere Informationen finden Sie unter Erweitern der Kontrolle über Fehlerbehandlung und -meldung.

Die Anwendung erfordert möglicherweise eine bestimmte automatische Behandlung von nicht verarbeitbaren Nachrichten, mit der die nicht verarbeitbaren Nachrichten in eine entsprechende Warteschlange verschoben werden, sodass der Dienst auf die restlichen Nachrichten in der Warteschlange zugreifen kann. Das einzige Szenario, in dem der Fehlerbehandlungsmechanismus zum Abhören auf Ausnahmen für nicht verarbeitbare Nachrichten verwendet werden kann, liegt vor, wenn die ReceiveErrorHandling-Einstellung auf Fault festgelegt ist. Das Beispiel der nicht verarbeitbaren Nachricht für Message Queuing 3.0 veranschaulicht dieses Verhalten. Im Folgenden werden die Schritte zur Behandlung nicht verarbeitbarer Nachrichten, einschließlich empfohlener Vorgehensweisen, umrissen:

  1. Stellen Sie sicher, dass die Einstellungen für nicht verarbeitbare Nachrichten den Anforderungen Ihrer Anwendung entsprechen. Stellen Sie beim Arbeiten mit den Einstellungen sicher, dass Sie die Unterschiede zwischen den Funktionen von Message Queuing unter Windows Vista, Windows Server 2003 und Windows XP verstehen.

  2. Implementieren Sie falls erforderlich den IErrorHandler, um Fehler mit nicht verarbeitbaren Nachrichten zu behandeln. Das das Festlegen von ReceiveErrorHandling auf Fault einen manuellen Mechanismus zum Verschieben der nicht verarbeitbaren Nachricht aus der Warteschlange oder zum Korrigieren eines Problems mit externen Abhängigkeiten erfordert, besteht die typische Nutzung darin, den IErrorHandler zu implementieren, wenn ReceiveErrorHandling auf Fault festgelegt ist, wie im folgenden Code gezeigt:

    class PoisonErrorHandler : IErrorHandler
    {
        public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
        {
            // No-op -We are not interested in this. This is only useful if you want to send back a fault on the wire…not applicable for queues [one-way].
        }
    
        public bool HandleError(Exception error)
        {
            if (error != null && error.GetType() == typeof(MsmqPoisonMessageException))
            {
                Console.WriteLine(" Poisoned message -message look up id = {0}", ((MsmqPoisonMessageException)error).MessageLookupId);
                return true;
            }
    
            return false;
        }
    }
    
  3. Erstellen Sie ein PoisonBehaviorAttribute, das das Dienstverhalten verwenden kann. Das Verhalten installiert den IErrorHandler auf dem Verteiler. Siehe nachstehendes Codebeispiel.

    public class PoisonErrorBehaviorAttribute : Attribute, IServiceBehavior
    {
        Type errorHandlerType;
    
        public PoisonErrorBehaviorAttribute(Type errorHandlerType)
        {
            this.errorHandlerType = errorHandlerType;
        }
    
        void IServiceBehavior.Validate(ServiceDescription description, ServiceHostBase serviceHostBase)
        {
        }
    
        void IServiceBehavior.AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, BindingParameterCollection parameters)
        {
        }
    
        void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase)
        {
            IErrorHandler errorHandler;
    
            try
            {
                errorHandler = (IErrorHandler)Activator.CreateInstance(errorHandlerType);
            }
            catch (MissingMethodException e)
            {
                throw new ArgumentException("The errorHandlerType specified in the PoisonErrorBehaviorAttribute constructor must have a public empty constructor", e);
            }
            catch (InvalidCastException e)
            {
                throw new ArgumentException("The errorHandlerType specified in the PoisonErrorBehaviorAttribute constructor must implement System.ServiceModel.Dispatcher.IErrorHandler", e);
            }
    
            foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
            {
                ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher;
                channelDispatcher.ErrorHandlers.Add(errorHandler);
            }
        }
    }
    
  4. Stellen Sie sicher, dass der Dienst mit dem Verhaltensattribut für nicht verarbeitbare Nachrichten kommentiert wird.

Wenn außerdem das ReceiveErrorHandling auf Fault festgelegt ist, tritt beim ServiceHost ein Fehler auf, wenn dieser auf die nicht verarbeitbare Nachricht stößt. Sie können sich dem Fehlerereignis zuwenden und den Dienst herunterfahren, Korrekturmaßnahmen treffen und neu starten. Beispielsweise kann die LookupId in der MsmqPoisonMessageException, die an den IErrorHandler weitergegeben wurde, notiert werden. Tritt nun beim Diensthost ein Fehler auf, können Sie die System.Messaging-API verwenden, um die Nachricht mithilfe der LookupId aus der Warteschlange zu empfangen, die Nachricht aus der Warteschlange zu entfernen und die Nachricht in einem externen Speicher oder einer anderen Warteschlange zu speichern. Sie können dann den ServiceHost neu starten, um die normale Verarbeitung fortzusetzen. Dieses Verhalten wird unter Behandlung nicht verarbeitbarer Nachrichten in MSMQ 4.0 veranschaulicht.

Transaktionstimeout und nicht verarbeitbare Nachrichten

Eine Klasse von Fehlern kann zwischen dem Wartenschlangentransportkanal und dem Benutzercode auftreten. Diese Fehler können durch Zwischenschichten erkannt werden, beispielsweise die Nachrichtensicherheitsschicht oder die Dienstverteilungslogik. So stellen beispielsweise ein in der SOAP-Sicherheitsschicht erkanntes fehlendes X.509-Zertifikat und eine fehlende Aktion Fälle dar, in denen die Nachricht nicht an die Anwendung verteilt wird. In diesem Fall wird die Nachricht durch das Dienstmodell wieder abgelegt. Da die Nachricht in einer Transaktion gelesen wird und ein Ergebnis für diese Transaktion nicht geliefert werden kann, kommt es letztlich zum Timeout der Transaktion, sie wird abgebrochen, und die Nachricht wird wieder in die Warteschlange zurückgestellt. Mit anderen Worten, bei einer bestimmten Klasse von Fehlern bricht die Transaktion nicht sofort ab, sondern wartet, bis die Transaktion einen Timeout erreicht. Sie können den Transaktionstimeout für einen Dienst ändern, indem Sie ServiceBehaviorAttribute verwenden.

Um den Transaktionstimeout computerweit zu ändern, ändern Sie die Datei „machine.config“, und legen Sie den entsprechenden Transaktionstimeout fest. Beachten Sie, dass die Transaktion je nach dem in der Transaktion festgelegten Timeout schließlich abbricht, in die Warteschlange zurückkehrt und ihr Abbruchzähler erhöht wird. Schließlich wird die Nachricht nicht verarbeitbar, und die richtige Disposition wird entsprechend den Benutzereinstellungen gewählt.

Sitzungen und nicht verarbeitbare Nachrichten

Eine Sitzung durchläuft die gleichen Wiederholungsprozeduren und Prozeduren zur Behandlung nicht verarbeitbarer Nachrichten wie eine einzelne Nachricht. Die zuvor aufgeführten Eigenschaften für nicht verarbeitbare Nachrichten gelten auch für die ganze Sitzung, d. h., dass die gesamte Sitzung wiederholt wird und schließlich in einer Warteschlange für potenziell schädliche Nachrichten oder in der Absenderwarteschlange für unzustellbare Nachrichten platziert wird, wenn die Nachricht abgelehnt wird.

Batchverarbeitung und nicht verarbeitbare Nachrichten

Wenn eine Nachricht zu einer nicht verarbeitbaren Nachricht wird und Teil eines Batches ist, wird für den gesamten Batch ein Rollback durchgeführt, und der Kanal kehrt zum Lesen einzelner Nachrichten zurück. Weitere Informationen zur Batchverarbeitung finden Sie unter Batchverarbeitung von Nachrichten in einer Transaktion.

Behandlung nicht verarbeitbarer Nachrichten für Nachrichten in einer Warteschlange für potenziell schädliche Nachrichten

Die Behandlung nicht verarbeitbarer Nachrichten ist nicht damit beendet, dass eine Nachricht in die Warteschlange für potenziell schädliche Nachrichten eingefügt wird. Die Nachrichten in der Warteschlange für potenziell schädliche Nachrichten müssen immer noch gelesen und behandelt werden. Beim Lesen von Nachrichten aus der endgültigen Warteschlange für potenziell schädliche Nachrichten können Sie eine Teilmenge der Einstellungen zur Behandlung nicht verarbeitbarer Nachrichten verwenden. Die anwendbaren Einstellungen sind ReceiveRetryCount und ReceiveErrorHandling. Sie können ReceiveErrorHandling auf "Drop", "Reject" oder "Fault" festlegen. MaxRetryCycles wird ignoriert, und es wird eine Ausnahme ausgelöst, wenn ReceiveErrorHandling auf {3>Move<3} festgelegt wird.

Unterschiede zwischen Windows Vista, Windows Server 2003 und Windows XP

Wie bereits erwähnt, gelten nicht alle Einstellungen für die Behandlung von nicht verarbeitbaren Nachrichten für Windows Server 2003 und Windows XP. Die folgenden wichtigen Unterschiede zwischen Message Queuing unter Windows Server 2003, Windows XP und Windows Vista sind für die Behandlung von nicht verarbeitbaren Nachrichten relevant:

  • Message Queuing unter Windows Vista unterstützt Unterabfragen, während Windows Server 2003 und Windows XP keine Unterabfragen unterstützen. Untergeordnete Warteschlangen werden zur Behandlung nicht verarbeitbarer Nachrichten verwendet. Die Wiederholungswarteschlangen und die Warteschlange für potenziell schädliche Nachrichten sind untergeordnete Warteschlangen der Anwendungswarteschlange, die basierend auf den Einstellungen für die Behandlung nicht verarbeitbarer Nachrichten erstellt wird. Die Eigenschaft MaxRetryCycles bestimmt, wie viele untergeordnete Wiederholungwarteschlangen erstellt werden sollen. Daher werden MaxRetryCycles ignoriert, wenn sie unter Windows Server 2003 oder Windows XP ausgeführt wird, und ReceiveErrorHandling.Move ist nicht zulässig.

  • Message Queuing unter Windows Vista unterstützt negative Bestätigungen, während dies für Windows Server 2003 und Windows XP nicht gilt. Eine negative Bestätigung vom empfangenden Warteschlangen-Manager bewirkt, dass der sendende Warteschlangen-Manager die abgelehnte Nachricht in die Warteschlange für unzustellbare Nachrichten einstellt. Daher ist ReceiveErrorHandling.Reject mit Windows Server 2003 und Windows XP nicht zulässig.

  • Message Queuing unter Windows Vista unterstützt eine Nachrichteneigenschaft, die zählt, wie oft die Nachrichtenzustellung versucht wird. Diese Eigenschaft für die Abbruchanzahl ist unter Windows Server 2003 und Windows XP nicht verfügbar. WCF verwaltet die Abbruchanzahl im Arbeitsspeicher. Deshalb enthält diese Eigenschaft möglicherweise keinen exakten Wert, wenn dieselbe Nachricht von mehreren WCF-Diensten in einer Farm gelesen wird.

Siehe auch