Patroon Compenserende transactie
Maak werk ongedaan dat is uitgevoerd door een reeks stappen, die samen een uiteindelijke consistente bewerking definiëren, als een of meer stappen mislukken. Bewerkingen die het uiteindelijke consistentiemodel volgen, worden vaak gevonden in cloudtoepassingen die complexe bedrijfsprocessen en werkstromen implementeren.
Context en probleem
Toepassingen die in de cloud worden uitgevoerd, wijzigen vaak gegevens. Deze gegevens kunnen zijn verdeeld over verschillende gegevensbronnen die zijn ondergebracht in verschillende geografische locaties. Om in een gedistribueerde omgeving conflicten te voorkomen en prestaties te verbeteren, mag een toepassing geen sterke transactionele consistentie bieden. In plaats daarvan moet de toepassing uiteindelijke consistentie implementeren. In dit model bestaat een typische zakelijke bewerking uit een reeks afzonderlijke stappen. Terwijl deze stappen worden uitgevoerd, is de algehele weergave van de systeemstatus mogelijk inconsistent, maar wanneer de bewerking is voltooid en alle stappen zijn uitgevoerd, moet het systeem weer consistent worden.
De Data Consistency Primer (Inleiding over gegevensconsistentie, Engelstalig) bevat informatie over waarom gedistribueerde transacties niet goed schalen en de principes van het uiteindelijke consistentiemodel.
Hoe u moet omgaan met een stap die is mislukt, is een uitdaging in het uiteindelijke consistentiemodel. In dit geval kan het nodig zijn om al het werk dat tijdens de vorige stappen in de bewerking is voltooid ongedaan te maken. De gegevens kunnen echter niet zomaar worden teruggedraaid, omdat andere gelijktijdige exemplaren van de toepassing deze mogelijk hebben gewijzigd. Zelfs wanneer de gegevens niet door een gelijktijdig exemplaar zijn gewijzigd, is het ongedaan maken van een stap mogelijk niet gewoon een kwestie van alleen maar de oorspronkelijke status herstellen. Het kan noodzakelijk zijn om verschillende bedrijfsspecifieke regels toe te passen (zie de reiswebsite die in de sectie Voorbeeld wordt beschreven).
Als een bewerking die uiteindelijke consistentie implementeert uit verschillende heterogene gegevensopslagplaatsen bestaat, vereist het ongedaan maken van de stappen in de bewerking dat elke gegevensopslag moet worden bezocht. Het werk dat in elke gegevensopslag is uitgevoerd, moet op een betrouwbare manier ongedaan worden gemaakt om te voorkomen dat het systeem inconsistent blijft.
Het kan zijn dat niet alle gegevens die worden beïnvloed door een bewerking die uiteindelijke consistentie implementeert, zijn ondergebracht in een database. In een servicegerichte architectuur kan een bewerking een actie in een service aanroepen en een wijziging in de status van die service veroorzaken. Om de bewerking ongedaan te maken, moet deze statuswijziging ook ongedaan worden gemaakt. Dit kan bestaan uit het opnieuw aanroepen van de service en het uitvoeren van een andere actie die de effecten van de eerste terugdraait.
Oplossing
De oplossing is de implementatie van een compenserende transactie. De stappen in een compenserende transactie moeten de effecten van de stappen in de oorspronkelijke bewerking ongedaan maken. Het kan zijn dat een compenserende transactie de huidige status niet kan vervangen met de status waarin het systeem zich in het begin van de bewerking bevond, omdat deze benadering wijzigingen kan overschrijven die door andere gelijktijdige exemplaren van een toepassing zijn gemaakt. In plaats daarvan moet er gebruik worden gemaakt van een intelligent proces dat rekening houdt met werkzaamheden die door gelijktijdige exemplaren worden uitgevoerd. Dit proces is doorgaans toepassingsspecifiek en wordt aangestuurd door de aard van het werk dat door de oorspronkelijke bewerking wordt uitgevoerd.
Een algemene aanpak is het gebruik van een werkstroom om een uiteindelijke consistente bewerking die compensatie vereist te implementeren. Als de oorspronkelijke bewerking wordt voortgezet, registreert het systeem informatie over elke stap en hoe de werkzaamheden van deze stap ongedaan kunnen worden gemaakt. Als de bewerking op een bepaald punt mislukt, wordt de werkstroom teruggespoeld door de stappen die zijn voltooid en wordt het werk uitgevoerd dat elke stap terugdraait. Houd er rekening mee dat een compenserende transactie het werk mogelijk niet precies in de omgekeerde volgorde van de oorspronkelijke bewerking ongedaan hoeft te maken en dat u enkele stappen voor het ongedaan maken parallel kunt uitvoeren.
Deze aanpak is vergelijkbaar met de Sagas-strategie. Deze wordt in de blog van Clemens Vasters besproken.
Een compenserende transactie is ook een uiteindelijke consistente bewerking en deze kan ook mislukken. Het systeem moet de compenserende transactie op het moment van de fout kunnen hervatten en doorgaan. Het kan nodig zijn om een stap die is mislukt te herhalen. De stappen in een compenserende transactie moeten dus worden gedefinieerd als idempotente opdrachten. Zie Idempotency Patterns (Idempotentiepatronen) op de blog van Jonathan Jonathan voor meer informatie.
In sommige gevallen is het niet mogelijk om te herstellen van een stap die is mislukt behalve via handmatig ingrijpen. In deze situaties moet het systeem een waarschuwing activeren en zoveel mogelijk informatie over de reden voor de fout geven.
Problemen en overwegingen
Beschouw de volgende punten als u besluit hoe u dit patroon wilt implementeren:
Het is mogelijk niet eenvoudig om te bepalen wanneer een stap in een bewerking die uiteindelijke consistentie implementeert is mislukt. Een stap hoeft niet onmiddellijk te mislukken, maar in plaats daarvan kan deze blokkeren. Het kan noodzakelijk zijn om een vorm van time-outmechanisme te implementeren.
Compensatielogica is niet eenvoudig te generaliseren. Een compenserende transactie is toepassingsspecifiek. Het is afhankelijk van de vraag of de toepassing voldoende informatie bevat om de effecten van elke stap in een mislukte bewerking ongedaan te maken.
U moet de stappen in een compenserende transactie definiëren als idempotente opdrachten. Hierdoor kunnen de stappen worden herhaald als de compenserende transactie zelf mislukt.
De infrastructuur die de stappen beheert in de oorspronkelijke bewerking en de compenserende transactie moeten flexibel zijn. Deze moet de benodigde informatie om te compenseren voor een mislukte stap niet verliezen en moet de voortgang van de compensatielogica op een betrouwbare manier bewaken.
Een compenserende transactie retourneert de gegevens in het systeem niet per se naar de status waarin het systeem zich in het begin van de oorspronkelijke bewerking bevond. In plaats daarvan compenseert deze voor het werk dat door de stappen succesvol is voltooid voordat de bewerking mislukte.
De volgorde van de stappen in de compenserende transactie hoeft niet per se het exacte tegenovergestelde van de stappen in de oorspronkelijke bewerking te zijn. De ene gegevensopslagplaats is bijvoorbeeld mogelijk gevoeliger voor inconsistenties dan de andere. De stappen in de compenserende transactie die de wijzigingen aan deze opslag ongedaan maken, moeten daarom eerst plaatsvinden.
Als u een kortlopende, op een time-out gebaseerde vergrendeling op elke resource plaatst die is vereist om een bewerking te voltooien en deze resources van tevoren verkrijgt, is de kans groter dat de algehele activiteit slaagt. Het werk moet worden uitgevoerd nadat alle resources zijn verkregen. Alle acties moeten worden voltooid voordat de vergrendelingen verlopen.
Overweeg het gebruik van logica Opnieuw proberen, die vergevingsgezinder is dan normaal om fouten die een compenserende transactie activeren te minimaliseren. Als een stap in een bewerking die uiteindelijke consistentie implementeert mislukt, behandelt u de fout als een tijdelijke uitzondering en herhaalt u de stap. Alleen als een stap herhaaldelijk of permanent mislukt, stopt u de bewerking en start u een compenserende transactie.
Veel uitdagingen die komen kijken bij de implementatie van een compenserende transactie zijn dezelfde als die waarmee u te maken krijgt bij de implementatie van uiteindelijke consistentie. Zie de sectie Considerations for Implementing Eventual Consistency (Overwegingen voor de implementatie van uiteindelijke consistentie, Engelstalig) in de Data Consistency Primer (Inleiding over gegevensconsistentie, Engelstalig) voor meer informatie.
Wanneer dit patroon gebruiken
Gebruik dit patroon alleen voor bewerkingen die ongedaan moeten worden gemaakt als deze mislukken. Ontwerp, indien mogelijk, oplossingen om de complexiteit van het vereisen van compenserende transacties te voorkomen.
Voorbeeld
Op een reiswebsite kunnen klanten reisroutes boeken. Een enkele route kan bestaan uit een reeks vluchten en hotels. Een klant die van Seattle naar Londen reist en vervolgens naar Parijs vliegt, kan de volgende stappen uitvoeren bij het maken van een route:
- Boek een stoel op vlucht V1 van Seattle naar Londen.
- Boek een stoel op vlucht V2 van Londen naar Parijs.
- Boek een stoel op vlucht V3 van Parijs naar Seattle.
- Reserveer een kamer in hotel H1 in Londen.
- Reserveer een kamer in hotel H2 in Parijs.
Deze stappen vormen een uiteindelijke consistente bewerking, hoewel elke stap uit een aparte actie bestaat. Daarom moet het systeem deze stappen uitvoeren, maar ook de tegenovergestelde bewerkingen vastleggen die nodig zijn om elke stap ongedaan te maken als de klant besluit de route te annuleren. De stappen die nodig zijn om de tegenovergestelde bewerkingen uit te voeren, kunnen vervolgens als een compenserende transactie worden uitgevoerd.
U ziet dat de stappen in de compenserende transactie niet per se het exacte tegenovergestelde van de oorspronkelijke stappen zijn en de logica in elke stap in de compenserende transactie moet rekening houden met eventuele bedrijfsspecifieke regels. Als een stoelreservering op een vlucht bijvoorbeeld wordt geannuleerd, hoeft dit niet te betekenen dat de klant het recht heeft op volledige terugbetaling. Op de afbeelding ziet u het genereren van een compenserende transactie om een langlopende transactie om een reisroute te boeken ongedaan te maken.

Notitie
De stappen in de compenserende transactie kunnen parallel worden uitgevoerd. Dit is afhankelijk van hoe u de compensatielogica voor elke stap hebt ontworpen.
In veel bedrijfsoplossingen vereist het mislukken van één stap niet altijd het terugdraaien van het systeem met een compenserende transactie. Als bijvoorbeeld de klant in het scenario van de reiswebsite —na het boeken van vlucht V1, V2 en V3— geen kamer in hotel H1 kan reserveren, is het beter om de klant een kamer in een ander hotel in dezelfde stad te bieden dan de vluchten te annuleren. De klant kan er nog steeds voor kiezen om te annuleren (de compenserende transactie wordt dan uitgevoerd en de reserveringen voor vlucht V1, V2 en V3 worden ongedaan gemaakt), maar deze beslissing moet door de klant worden genomen en niet door het systeem.
Verwante informatie
De volgende patronen en richtlijnen zijn mogelijk ook relevant bij de implementatie van dit patroon:
Gegevensconsistentie-primer. Het patroon Compenserende transactie wordt vaak gebruikt om bewerkingen die het uiteindelijke consistentiemodel implementeren ongedaan te maken. Deze inleiding bevat informatie over de voordelen en consequenties van uiteindelijke consistentie.
Scheduler-Agent-Supervisor-patroon. Hierin wordt beschreven hoe u flexibele systemen implementeert die bedrijfsbewerkingen uitvoeren die gebruikmaken van gedistribueerde services en resources. Soms is het nodig om de werkzaamheden die door een bewerking zijn uitgevoerd ongedaan te maken met behulp van een compenserende transactie.
Patroon voor opnieuw proberen. Het uitvoeren van compenserende transacties kan duur. Het is mogelijk om het gebruik hiervan te minimaliseren door een effectief beleid te implementeren waarbij mislukte bewerkingen opnieuw worden geprobeerd met het patroon Opnieuw proberen.