Ga naar hoofdinhoud

Herstel

In dit document worden een aantal wijzen van herstel beschreven binnen een event sourcing paradigma, met de voordelen en nadelen.

Huidige denkrichting: Voor veel voorkomende gevallen oplossing 1, als achtervang oplossing 3.

1. Specifieke commando's en gevolgen

Elke mogelijke door de business erkend herstelactie wordt als eigen command en daarop volgende gevolgen gebouwd.

Voordelen:

  • Expliciet en gestructureerd vastgelegd wat er hersteld is (en waarom).

Nadelen:

  • Voor elk hersteltype moet software gebouwd worden.

Implementatie

Elk specifieke herstelgevolg moet een specifieke situatie, een collectie van eerdere gevolgen, expliciet herstellen. Dit moet ook als zodanig vastgelegd en gevalideerd worden. Met herstel bovenschrijf je altijd een eerder tijdvak: het moet dus heel duidelijk zijn welk tijdvak je bovenschrijft.

Minimale implementatie

Er zijn een aantal scenario's waarin deze wijze van implementatie min of meer vereist is:

  • Verandering van identificerende gegevens
  • Verschuiving van tijdstippen
  • (Belangrijke) degistratie

2. Herstel via 'subcommands' ('de Kadaster-Koers methode')

Herstel wordt als generiek command geïmplementeerd, maar wordt aan de commandkant opgesplitst in subcommando's die reguliere businesscommando's representeren.

Voorbeeld: Er is een overdracht geweest van A naar B. Later blijkt echter dat de overdracht van A naar C had moeten plaatsvinden. Het herstelcommando bevat een subcommando 'overdracht', dat het systeem instrueert om het belang over te dragen van B naar C.

Voordelen:

  • Het aantal herstelmogelijkheden bestaat uit je gehele scala aan 'reguliere' commando's.
  • Hergebruik van validatieregels van 'reguliere' commando's is mogelijk.

Nadelen:

  • Vanwege de validatieregels is het moeilijker voor medewerkers de gehele tijdlijn te herstellen (en wordt bij Koers vaak gekozen voor herstel van de actuele situatie).
  • De oorspronkelijk bedoelde mutatie (de transactie) is in veel gevallen niet herleidbaar.
  • Wat er precies hersteld is en waarom is vaak moeilijk te herleiden.
  • Meerdere gevolgen samen vormen het herstel, met als gevolg dat in de verwerking van gevolgen voor 1 herstelactie meerdere snapshots geproduceerd worden, waarbij er tijdvakken 'deels hersteld' ontstaan.

3. Herstel via 'subgevolgen'

Herstel wordt uitgevoerd door 1 herstelgevolg toe te voegen dat 1 of meerdere reguliere gevolgen als 'subgevolgen' bevat. Deze subgevolgen dienen de eerder geproduceerde gevolgen te bovenschrijven. In feite teken je vanaf het aangegeven geldigheidstijdstip een nieuwe tijdlijn waarin je aangeeft hoe het had moeten zijn.

In het voorbeeld van de foute overdracht van A naar B, produceer je 1 herstelgevolg, dat een subgevolg overdracht bevat waarin staat dat het (op datzelfde moment) een overdracht van A naar C is.

Voordelen:

  • Elke tijdlijn kan bovenschreven (append only) worden met nieuwe gevolgen.
  • De oorspronkelijk bedoelde mutaties zijn duidelijk herleidbaar.
  • Herstel kan als 1 gevolg vastgelegd worden en als 1 databasetransactie verwerkt worden in projecties. 1 registratietijdstip en 1 beschikbaarheidstijdstip voor het hele herstel dus.

Nadelen:

  • Validatie van herstelcommando is ingewikkeld.
  • Wat er precies hersteld is en waarom is moeilijk te herleiden.
  • In projecties leiden subgevolgen tot extra complexiteit in de audit trail van de projectie.
  • Als tijdstippen 'schuiven' in de herstelgevolgen kan dat leiden tot complexe verwerking van gevolgen.

Conceptuele wijzen van herstel

Om herstel uit te voeren op een manier die de 'in de echte wereld bedoelde' geldigheidstijdslijn reproduceert dient de gemaakte fout eerst ongedaan gemaakt te worden voordat de mutatie 'zoals bedoeld' uitgevoerd kan worden. Dit kan op 2 manieren:

  1. vanuit de actuele (foutieve) state alle fouten terugboeken tot een correcte state in het verleden, om vervolgens de correcte mutaties door te voeren. -> Van a naar b had a naar c moeten zijn: We boeken terug van b naar a om de mutatie zoals bedoeld (a naar c) uit te kunnen voeren.

  2. Foutieve state laten voor wat het is, en teruggaan naar een punt in de tijd waar de state correct was, om vervolgens de oude state te 'bovenschrijven' -> van a naar b -> 'terug naar a' / 'opnieuw vanaf a' -> van a naar c

    Dit is precies wat de operatie recreateToUpend doet: de voorganger in geldigheid dient als uitgangspunt, de foutieve snapshot wordt genegeerd en de toestand wordt opnieuw opgebouwd.

Snapshot-operaties bij herstel

Het snapshot-mechanisme kent vijf operaties. Drie daarvan zijn specifiek relevant bij herstel:

  • newToUpend — bij herstel verschijnt een entiteit die er eerder niet was
  • updateToAmend — een bestaand tijdvak wordt bovenschreven op basis van de reeds geregistreerde toestand
  • recreateToUpend — de toestand wordt opnieuw opgebouwd vanuit het punt vóór de fout

Op verschillende manieren kijken naar herstel

Vanuit de query-kant zijn er meerdere manieren om te kijken naar herstel:

  1. Je kan geïnteresseerd zijn in hoe het had moeten zijn.
  2. Je kan geïnteresseerd zijn in wat er precies hersteld is.

Ten behoeve van het eerste perspectief is het handig om bij de afhandeling van gevolgen de gevolgen te hebben zoals ze hadden moeten zijn. Dit maakt het relatief eenvoudig om de 'in de echte wereld' bedoelde tijdlijn te reproduceren in een projectie, en zo te voorzien in deze querybehoefte.

De gevolgen 'zoals ze hadden moeten zijn' maken het echter onduidelijk wat er precies hersteld is, aangezien deze ook de niet-herstelde gegevens bevatten. Andersom: enkel de herstelde gegevens in gevolgen maken de afhandeling van gevolgen voor het eerste perspectief ingewikkeld. Het wordt aan de projectiekant veel moeilijker om de 'in de echte wereld' bedoelde tijdlijn te reproduceren.

Oplossing: In gevolg zowel het specifieke herstel als de het bedoelde gevolg bewaren. Als je in het herstelcommand vastlegt welke gevolgen hersteld moeten worden en wat de hersteloperatie is, dan is het niet moeilijk om in het gevolg (impliciet of expliciet) zowel vast te leggen wat de exacte correctie is én hoe het gevolg had moeten zijn.