Mönster för kompenserande transaktion

Ångra arbete som utförts i en serie steg och som tillsammans eventuellt definierar en konsekvent åtgärd, om ett eller flera av stegen misslyckas. Åtgärder som följer modellen för eventuell konsekvens finns vanligtvis i molnbaserade program som implementerar komplexa affärsprocesser och arbetsflöden.

Kontext och problem

Program som körs i molnet ändrar ofta data. Dessa data kan spridas till flera datakällor på olika geografiska platser. För att undvika konkurrens och förbättra prestanda i en distribuerad miljö, bör stark transaktionskonsekvens undvikas av ett program. I stället bör eventuell konsekvens implementeras av programmet. I den här modellen består en typisk affärsåtgärd av en serie olika steg. När dessa steg utförs kan den övergripande vyn av systemets tillstånd vara inkonsekvent, men systemet blir konsekvent igen när åtgärden och alla stegen har slutförts.

introduktionssidan om datakonsekvens kan du läsa om varför skalning inte fungerar så bra för distribuerade transaktioner, samt principerna för eventuell konsekvens.

En utmaning med modellen för eventuell konsekvens är hanteringen av steg som misslyckas. I dessa fall kan det vara nödvändigt att ångra allt arbete som genomförts i de föregående stegen i åtgärden. Men data kan inte återställas bara på grund av att de har ändrats av programmets andra samtidiga instanser. Även om data inte har ändrats av en samtidig instans, kan åtgärden att ångra ett steg innebära mer än att bara återställa det ursprungliga tillståndet. Det kan vara nödvändigt att tillämpa olika företagsspecifika regler (se exemplet med webbplatsen för bokning av resor).

Om en åtgärd där eventuell konsekvens implementeras omfattar flera heterogena datalager, krävs det att varje datalager bearbetas efter varandra när stegen i åtgärden ångras. Arbetet som utförs i varje datalager måste ångras på ett tillförlitligt sätt för att förhindra att systemet fortsätter att vara inkonsekvent.

Det är inte säkert att alla data som påverkas av en åtgärd som implementerar eventuell konsekvens finns i en databas. I en miljö med serviceorienterad arkitektur (SOA) kan en åtgärd anropa en åtgärd i en tjänst, och därmed orsaka en förändring i tjänstens tillstånd. Om du vill ångra åtgärden måste även den här tillståndsändringen ångras. Det kan innebära att anropa tjänsten igen och utföra en annan åtgärd som upphäver effekterna av den första åtgärden.

Lösning

Lösningen är att implementera en kompenserande transaktion. Stegen i en kompenserande transaktion måste ångra effekterna av stegen i den ursprungliga åtgärden. Det är inte säkert att en kompenserande transaktion bara kan ersätta det aktuella tillståndet med systemets tillstånd innan åtgärden, eftersom detta kan innebära att skriva över ändringar som gjorts av andra samtidiga instanser av ett program. I stället måste det vara en intelligent process som tar allt arbete som utförts av samtidiga instanser med i beräkningen. Den här processen brukar vara programspecifik och baserad på den typ av arbete som utförts genom den ursprungliga åtgärden.

En vanlig metod är att använda ett arbetsflöde för att implementera en eventuell konsekvens-åtgärd som kräver kompensation. Allt eftersom den ursprungliga åtgärden fortsätter registrerar systemet information om varje steg och hur arbetet som utförs av steget kan ångras. Om åtgärden vid någon punkt misslyckas går arbetsflödet bakåt genom stegen som har slutförts och utför det arbete som gör att varje steg ångras. Observera att en kompenserande transaktion kanske inte behöver ångra arbetet i den exakta omvända ordningen som i den ursprungliga åtgärden, och att vissa av stegen för att ångra möjligen kan utföras parallellt.

Den här metoden liknar Den Strategis-strategi som beskrivs i Clemens Vasters blogg.

En kompenserande transaktion är också en eventuell konsekvens-åtgärd och kan misslyckas. Systemet bör kunna återuppta den kompenserande transaktionen där felet inträffade och fortsätta. Ett steg som misslyckats kan behöva upprepas, så stegen i en kompenserande transaktion bör definieras som idempotenta kommandon. Mer information finns i Idempotency Patterns (Idempotensmönster) på Jonathan Jonathans blogg.

I vissa fall kanske det inte går att återuppta arbetet från ett steg som misslyckats utan att ta till manuella åtgärder. I sådana situationer ska systemet avisera om detta och ange så mycket information som möjligt om orsaken till felet.

Problem och överväganden

Tänk på följande när du bestämmer hur du ska implementera mönstret:

Det kan vara svårt att avgöra när ett steg misslyckas i en åtgärd där eventuell konsekvens implementeras. Ett steg kanske inte misslyckas direkt utan blockerar i stället. Det kan vara nödvändigt att implementera någon form av timeout-mekanism.

– Kompensationslogik är inte enkel att generalisera. En kompenserande transaktion är programspecifik. Den är beroende av att programmet innehåller tillräckligt med information för att kunna ångra effekterna av varje steg i en misslyckad åtgärd.

Stegen i en kompenserande transaktion ska definieras som idempotenta kommandon. Då kan stegen upprepas om den kompenserande transaktionen skulle misslyckas.

Infrastrukturen som hanterar stegen i den ursprungliga åtgärden och den kompenserande transaktionen måste vara elastisk. Den måste bevara informationen som krävs för att kompensera för ett misslyckat steg, samt övervaka förloppet för kompensationslogiken på ett tillförlitligt sätt.

En kompenserande transaktion återställer inte nödvändigtvis systemets data till samma tillstånd som innan den ursprungliga åtgärden. I stället kompenseras det arbete som hann utföras i stegen innan åtgärden misslyckades.

Stegens ordning i den kompenserande transaktionen behöver inte vara den exakta motsatsen till stegen i den ursprungliga åtgärden. Till exempel kan ett datalager vara känsligare för inkonsekvenser än ett annat, och stegen i den kompenserande transaktionen som ångrar ändringarna i det här lagret bör därför genomföras först.

Genom att placera ett kortvarigt timeout-baserat lås på varje resurs som krävs för att slutföra en åtgärd, samt att skaffa de här resurserna i förväg, ökar sannolikheten för att den övergripande aktiviteten lyckas. Alla resurser måste skaffas innan arbetet kan utföras. Alla åtgärder måste slutföras innan tiden upphör.

Du kanske kan använda återförsökslogik som är mindre strikt än vanligt för att minimera fel som utlöser en kompenserande transaktion. Om ett steg i en åtgärd som implementerar eventuell konsekvens misslyckas kan du prova att hantera felet som ett tillfälligt undantag och upprepa steget. Avbryt endast åtgärden och initiera den kompenserande transaktionen om ett steg misslyckas upprepade gånger eller oåterkalleligt.

Många av utmaningarna med att implementera en kompenserande transaktion är desamma som för att implementera eventuell konsekvens. Mer information om att hantera eventuell konsekvens finns i avsnittet om överväganden på introduktionssidan om datakonsekvens.

När du ska använda det här mönstret

Det här mönstret ska bara användas för åtgärder som måste ångras om de misslyckas. Om det är möjligt ska lösningar utformas för att slippa ta till komplexa kompenserande transaktioner.

Exempel

Kunder kan boka sina resor på en resewebbplats. En resa kan bestå av flera flygsträckor och övernattningar. Anta att en kund ska resa från Seattle till London och vidare till Paris. Då ingår följande steg för att skapa resan:

  1. Boka en plats på flighten F1 från Seattle till London.
  2. Boka en plats på flighten F2 från London till Paris.
  3. Boka en plats på flighten F3 från Paris till Seattle.
  4. Boka ett rum på hotellet H1 i London.
  5. Boka ett rum på hotellet H2 i Paris.

De här stegen utgör en eventuell konsekvens-åtgärd, samtidigt som varje steg är en separat åtgärd. Förutom att genomföra stegen, måste systemet därför även registrera de motåtgärder som skulle behövas för att ångra varje steg ifall kunden bestämmer sig för att avboka resan. Stegen för att utföra motåtgärderna kan sedan köras som en kompenserande transaktion.

Observera att stegen i den kompenserande transaktionen kanske inte är den exakta motsatsen till de ursprungliga stegen, och logiken i varje steg i den kompenserande transaktion måste ta hänsyn till eventuella företagsspecifika regler. Att avboka en flygsträcka innebär till exempel kanske inte att kunden får alla pengarna tillbaka. Bilden visar hur en kompenserande transaktion genereras för att ångra en längre transaktion för en resebokning.

Generera en kompenserande transaktion för att ångra en längre transaktion för en resebokning.

Anteckning

Det kan vara möjligt att utföra stegen i den kompenserande transaktionen parallellt, beroende på hur du har utformat kompensationslogiken för varje steg.

I många affärslösningar innebär inte ett enda misslyckat steg alltid att systemet måste återställas genom en kompenserande transaktion. Om kunden till exempel inte kan boka ett rum på hotellet H1 efter att ha bokat flygen F1, F2 och F3 i scenariot med resewebbplatsen, är det bättre att erbjuda kunden ett rum på ett annat hotell i samma stad i stället för att ställa in flygresorna. Kunden kan ändå välja att avboka (i sådana fall körs den kompenserande transaktionen så att flygbokningarna F1, F2 och F3 ångras), men det här beslutet ska fattas av kunden – inte systemet.

Följande mönster och riktlinjer kan vara relevanta när du implementerar det här mönstret:

  • Introduktion till datakonsekvens. Mönstret för kompenserande transaktioner används ofta för att ångra åtgärder som implementerar eventuell konsekvens. Den här introduktionen innehåller information om fördelarna med eventuell konsekvens.

  • Mönstret Scheduler-Agent-Supervisor. Beskriver hur du implementerar elastiska system som utför affärsåtgärder som tillämpar distribuerade tjänster och resurser. Ibland kan det vara nödvändigt att ångra det arbete som utförts av en åtgärd med hjälp av en kompenserande transaktion.

  • Återförsöksmönster. Kompenserande transaktioner kan vara kostsamma att utföra, men det kan vara möjligt att minska användningen genom att implementera en princip för återförsök vid misslyckade åtgärder genom att följa återförsöksmönstret.