Dela via


Hantering av giftmeddelanden

Ett giftmeddelande är ett meddelande som har överskridit det maximala antalet leveransförsök till programmet. Den här situationen kan uppstå när ett köbaserat program inte kan bearbeta ett meddelande på grund av fel. För att uppfylla tillförlitlighetskraven tar ett köat program emot meddelanden under en transaktion. Om du avbryter transaktionen där ett köat meddelande togs emot lämnar du meddelandet i kön så att meddelandet görs om under en ny transaktion. Om problemet som orsakade att transaktionen avbröts inte korrigeras kan det mottagande programmet fastna i en loop som tar emot och avbryter samma meddelande tills det maximala antalet leveransförsök har överskridits och ett giftmeddelande resulterar.

Ett meddelande kan bli ett giftmeddelande av många skäl. De vanligaste orsakerna är programspecifika. Om ett program till exempel läser ett meddelande från en kö och utför viss databasbearbetning kan programmet misslyckas med att få ett lås på databasen, vilket gör att transaktionen avbryts. Eftersom databastransaktionen avbröts finns meddelandet kvar i kön, vilket gör att programmet läser om meddelandet en andra gång och gör ett nytt försök att hämta ett lås på databasen. Meddelanden kan också bli skadliga om de innehåller ogiltig information. En inköpsorder kan till exempel innehålla ett ogiltigt kundnummer. I dessa fall kan programmet frivilligt avbryta transaktionen och tvinga meddelandet att bli ett giftmeddelande.

I sällsynta fall kan meddelanden inte skickas till programmet. WCF-lagret (Windows Communication Foundation) kan hitta ett problem med meddelandet, till exempel om meddelandet har fel ram, ogiltiga autentiseringsuppgifter för meddelanden som är kopplade till det eller ett ogiltigt åtgärdshuvud. I dessa fall tar programmet aldrig emot meddelandet. Meddelandet kan dock fortfarande bli ett giftmeddelande och bearbetas manuellt.

Hantera giftmeddelanden

I WCF tillhandahåller hantering av giftmeddelanden en mekanism för ett mottagande program för att hantera meddelanden som inte kan skickas till programmet eller meddelanden som skickas till programmet, men som inte kan bearbetas på grund av programspecifika orsaker. Konfigurera hantering av giftmeddelanden med följande egenskaper i var och en av de tillgängliga köade bindningarna:

  • ReceiveRetryCount. Ett heltalsvärde som anger det maximala antalet gånger som ett meddelande ska skickas igen från programkön till programmet. Standardvärdet är 5. Detta är tillräckligt i de fall där ett omedelbart återförsök åtgärdar problemet, till exempel med ett tillfälligt dödläge i en databas.

  • MaxRetryCycles. Ett heltalsvärde som anger det maximala antalet återförsökscykler. En återförsökscykel består av att överföra ett meddelande från programkön till underfrågan för återförsök och, efter en konfigurerbar fördröjning, från återförsöksunderfrågan tillbaka till programkön för att återförsöka leveransen. Standardvärdet är 2. I Windows Vista provas meddelandet högst (ReceiveRetryCount +1) * (MaxRetryCycles + 1) gånger. MaxRetryCycles ignoreras på Windows Server 2003 och Windows XP.

  • RetryCycleDelay. Tidsfördröjningen mellan återförsökscykler. Standardvärdet är 30 minuter. MaxRetryCycles och RetryCycleDelay tillsammans tillhandahåller en mekanism för att lösa problemet där ett nytt försök efter en periodisk fördröjning löser problemet. Detta hanterar till exempel en låst raduppsättning i SQL Server-väntande transaktionsincheckning.

  • ReceiveErrorHandling. En uppräkning som anger vilken åtgärd som ska vidtas för ett meddelande som har misslyckats med leveransen efter att det maximala antalet återförsök har försökts. Värdena kan vara Fel, Släpp, Avvisa och Flytta. Standardalternativet är Fel.

  • Fel. Det här alternativet skickar ett fel till lyssnaren som orsakade ServiceHost felet. Meddelandet måste tas bort från programkön av någon extern mekanism innan programmet kan fortsätta att bearbeta meddelanden från kön.

  • Släppa. Det här alternativet släpper giftmeddelandet och meddelandet levereras aldrig till programmet. Om meddelandets TimeToLive egenskap har upphört att gälla nu kan meddelandet visas i avsändarens kö med obeställbara meddelanden. Annars visas inte meddelandet någonstans. Det här alternativet anger att användaren inte har angett vad som ska utföras om meddelandet går förlorat.

  • Avvisa. Det här alternativet är endast tillgängligt i Windows Vista. Detta instruerar Message Queuing (MSMQ) att skicka en negativ bekräftelse tillbaka till den sändande köhanteraren om att programmet inte kan ta emot meddelandet. Meddelandet placeras i köhanterarens kö med obeställbara meddelanden.

  • Flytta. Det här alternativet är endast tillgängligt i Windows Vista. Detta flyttar giftmeddelandet till en giftmeddelandekö för senare bearbetning av ett program för hantering av giftmeddelanden. Kön för giftmeddelanden är en underfråga i programkön. Ett program för hantering av giftmeddelanden kan vara en WCF-tjänst som läser meddelanden från giftkön. Giftkön är en underfråga i programkön och kan adresseras som net.msmq://<machine-name>/applicationQueue; poison, där datornamn är namnet på den dator där kön finns och applicationQueue är namnet på den programspecifika kön.

Följande är det maximala antalet leveransförsök som görs för ett meddelande:

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

  • (ReceiveRetryCount + 1) på Windows Server 2003 och Windows XP.

Kommentar

Inga återförsök görs för ett meddelande som har levererats.

Om du vill hålla reda på hur många gånger ett meddelande läss, underhåller Windows Vista en varaktig meddelandeegenskap som räknar antalet avbrutna och en egenskap för flyttantal som räknar antalet gånger meddelandet flyttas mellan programkön och underfrågorna. WCF-kanalen använder dessa för att beräkna antalet återförsök och antalet återförsökscykler. På Windows Server 2003 och Windows XP underhålls antalet avbrutna i minnet av WCF-kanalen och återställs om programmet misslyckas. Dessutom kan WCF-kanalen lagra antalet avbrutna för upp till 256 meddelanden i minnet när som helst. Om ett 257:e meddelande läss återställs det äldsta meddelandets antal avbrutna.

Egenskaperna abort count och move count är tillgängliga för tjänståtgärden via åtgärdskontexten. Följande kodexempel visar hur du kommer åt dem.

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 tillhandahåller två standardbindningar i kö:

  • NetMsmqBinding. En .NET Framework-bindning som lämpar sig för att utföra köbaserad kommunikation med andra WCF-slutpunkter.

  • MsmqIntegrationBinding. En bindning som lämpar sig för kommunikation med befintliga Message Queuing-program.

Kommentar

Du kan ändra egenskaper i dessa bindningar baserat på kraven för din WCF-tjänst. Hela mekanismen för hantering av giftmeddelanden är lokal för det mottagande programmet. Processen är osynlig för det sändande programmet om inte det mottagande programmet i slutändan stoppas och skickar en negativ bekräftelse tillbaka till avsändaren. I så fall flyttas meddelandet till avsändarens kö med obeställbara meddelanden.

Bästa praxis: Hantera MsmqPoisonMessageException

När tjänsten fastställer att ett meddelande är gift genererar den köade transporten LookupId en MsmqPoisonMessageException som innehåller giftmeddelandets.

Ett mottagande program kan implementera IErrorHandler gränssnittet för att hantera eventuella fel som programmet kräver. Mer information finns i Utöka kontroll över felhantering och rapportering.

Programmet kan kräva någon form av automatiserad hantering av giftmeddelanden som flyttar giftmeddelandena till en giftmeddelandekö så att tjänsten kan komma åt resten av meddelandena i kön. Det enda scenariot för att använda felhanterarmekanismen för att lyssna efter undantag för giftmeddelanden är när ReceiveErrorHandling inställningen är inställd på Fault. Giftmeddelandeexemplet för Message Queuing 3.0 visar det här beteendet. Följande beskriver de åtgärder som ska utföras för att hantera giftmeddelanden, inklusive metodtips:

  1. Se till att dina giftinställningar återspeglar kraven för ditt program. När du arbetar med inställningarna ska du se till att du förstår skillnaderna mellan funktionerna i Message Queuing i Windows Vista, Windows Server 2003 och Windows XP.

  2. Om det behövs implementerar du IErrorHandler för att hantera fel med giftmeddelanden. Eftersom inställningen ReceiveErrorHandling till Fault kräver en manuell mekanism för att flytta giftmeddelandet ut ur kön eller för att korrigera ett externt beroende problem, är den typiska användningen att implementera IErrorHandler när ReceiveErrorHandling är inställd på Fault, som visas i följande kod.

    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. Skapa ett PoisonBehaviorAttribute som tjänstbeteendet kan använda. Beteendet installerar IErrorHandler på avsändaren. Se följande kodexempel.

    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. Se till att tjänsten kommenteras med attributet giftbeteende.

Dessutom, om ReceiveErrorHandling är inställd på Fault, felen ServiceHost när du stöter på giftmeddelandet. Du kan ansluta till den felaktiga händelsen och stänga av tjänsten, vidta korrigerande åtgärder och starta om. I det MsmqPoisonMessageException som sprids till IErrorHandler kan till exempel LookupId noteras och när tjänstens värdfel, kan du använda API:et System.Messaging för att ta emot meddelandet från kön med hjälp av LookupId för att ta bort meddelandet från kön och lagra meddelandet i ett externt arkiv eller en annan kö. Du kan sedan starta om ServiceHost för att återuppta normal bearbetning. Hantering av giftmeddelanden i MSMQ 4.0 visar det här beteendet.

Timeout- och giftmeddelanden för transaktioner

En klass med fel kan inträffa mellan den köade transportkanalen och användarkoden. Dessa fel kan identifieras av lager däremellan, till exempel meddelandesäkerhetsskiktet eller tjänstens sändningslogik. Ett X.509-certifikat som saknas identifieras till exempel i SOAP-säkerhetsskiktet och en åtgärd som saknas är fall där meddelandet skickas till programmet. När detta händer släpper tjänstmodellen meddelandet. Eftersom meddelandet läss i en transaktion och ett resultat för transaktionen inte kan tillhandahållas, överskrider transaktionen till slut tidsgränsen, avbryter och meddelandet sätts tillbaka i kön. För en viss typ av fel avbryts med andra ord inte transaktionen omedelbart utan väntar tills transaktionen överskrider tidsgränsen. Du kan ändra tidsgränsen för transaktionen för en tjänst med hjälp av ServiceBehaviorAttribute.

Om du vill ändra tidsgränsen för transaktionen på datoromfattande basis ändrar du filen machine.config och anger lämplig tidsgräns för transaktionen. Det är viktigt att observera att transaktionen, beroende på den tidsgräns som angetts i transaktionen, så småningom avbryter och går tillbaka till kön och att antalet avbrutna ökar. Så småningom blir meddelandet gift och rätt borttagning görs enligt användarinställningarna.

Sessioner och giftmeddelanden

En session genomgår samma procedurer för återförsök och hantering av giftmeddelanden som ett enda meddelande. Egenskaperna som tidigare angavs för giftmeddelanden gäller för hela sessionen. Det innebär att hela sessionen görs om och går till en slutlig kö för giftmeddelanden eller avsändarens kö med obeställbara meddelanden om meddelandet avvisas.

Batchbearbetning och giftmeddelanden

Om ett meddelande blir ett giftmeddelande och ingår i en batch, återställs hela batchen och kanalen återgår till att läsa ett meddelande i taget. Mer information om batchbearbetning finns i Batcha meddelanden i en transaktion

Hantering av giftmeddelanden för meddelanden i en giftkö

Hanteringen av giftmeddelanden upphör inte när ett meddelande placeras i kön för giftmeddelanden. Meddelanden i kön för giftmeddelanden måste fortfarande läsas och hanteras. Du kan använda en delmängd av inställningarna för hantering av giftmeddelanden när du läser meddelanden från den slutliga giftunderfrågan. De tillämpliga inställningarna är ReceiveRetryCount och ReceiveErrorHandling. Du kan ställa in ReceiveErrorHandling på Släpp, Avvisa eller Fel. MaxRetryCycles ignoreras och ett undantag utlöses om ReceiveErrorHandling är inställt på Flytta.

Skillnader mellan Windows Vista, Windows Server 2003 och Windows XP

Som tidigare nämnts gäller inte alla inställningar för hantering av giftmeddelanden för Windows Server 2003 och Windows XP. Följande viktiga skillnader mellan Message Queuing på Windows Server 2003, Windows XP och Windows Vista är relevanta för hantering av giftmeddelanden:

  • Message Queuing i Windows Vista stöder underfrågor, medan Windows Server 2003 och Windows XP inte stöder underfrågor. Underfrågor används vid hantering av giftmeddelanden. Köerna för återförsök och giftkön är underfrågor till programkön som skapas baserat på inställningarna för hantering av giftmeddelanden. Avgör MaxRetryCycles hur många återförsöksunderfrågor som ska skapas. När du kör på Windows Server 2003 eller Windows XP MaxRetryCycles ignoreras därför och ReceiveErrorHandling.Move tillåts inte.

  • Message Queuing i Windows Vista stöder negativ bekräftelse, medan Windows Server 2003 och Windows XP inte gör det. En negativ bekräftelse från den mottagande köhanteraren gör att den sändande köhanteraren placerar det avvisade meddelandet i kön med obeställbara meddelanden. ReceiveErrorHandling.Reject Därför är inte tillåtet med Windows Server 2003 och Windows XP.

  • Message Queuing i Windows Vista stöder en meddelandeegenskap som håller antalet gånger som meddelandeleveransen görs. Egenskapen abort count är inte tillgänglig på Windows Server 2003 och Windows XP. WCF upprätthåller antalet misslyckade i minnet, så det är möjligt att den här egenskapen kanske inte innehåller ett korrekt värde när samma meddelande läss av mer än en WCF-tjänst i en servergrupp.

Se även