Replikerade korn
Ibland kan det finnas flera instanser av samma korn aktiva, till exempel när du använder ett multikluster och använder OneInstancePerClusterAttribute. JournaledGrain är utformad för att stödja replikerade instanser med minimal friktion. Den förlitar sig på att loggkonsekvensprovidrar kör de protokoll som krävs för att säkerställa att alla instanser är överens om samma händelsesekvens. I synnerhet tar den hand om följande aspekter:
Konsekventa versioner: Alla versioner av korntillståndet (förutom preliminära versioner) baseras på samma globala händelsesekvens. I synnerhet om två instanser ser samma versionsnummer ser de samma tillstånd.
Racinghändelser: Flera instanser kan samtidigt skapa ett evenemang. Konsekvensprovidern löser det här loppet och ser till att alla är överens om samma sekvens.
Meddelanden/reaktivitet: När en händelse har genererats vid enstaka instans uppdaterar konsekvensprovidern inte bara lagringen utan meddelar även alla andra korninstanser.
En allmän diskussion om konsekvensen finns i vår TechReport och GSP-uppsatsen (Global Sequence Protocol).
Villkorsstyrda händelser
Racinghändelser kan vara problematiska om de har en konflikt, dvs. bör inte båda genomföra av någon anledning. När du till exempel tar ut pengar från ett bankkonto kan två instanser självständigt fastställa att det finns tillräckligt med pengar för ett uttag och utfärda en uttagshändelse. Men kombinationen av båda händelserna kan övertrassera. För att undvika detta stöder API:et JournaledGrain
en RaiseConditionalEvent metod.
bool success = await RaiseConditionalEvent(
new WithdrawalEvent() { /* ... */ });
Villkorsstyrda händelser dubbelkollar om den lokala versionen matchar versionen i lagringen. Annars innebär det att händelsesekvensen har vuxit under tiden, vilket innebär att den här händelsen har förlorat en tävling mot någon annan händelse. I så fall läggs inte den villkorsstyrda händelsen till i loggen och RaiseConditionalEvent returnerar false.
Detta är analogt med användning av e-taggar med uppdateringar av villkorlig lagring, och ger på samma sätt en enkel mekanism för att undvika att händelser i konflikt begås.
Det är möjligt och klokt att använda både villkorsstyrda och ovillkorliga händelser för samma kornighet, till exempel en DepositEvent
och en WithdrawalEvent
. Insättningar behöver inte vara villkorade: även om en DepositEvent
förlorar en tävling behöver den inte avbrytas, men kan fortfarande läggas till i den globala händelsesekvensen.
Det räcker att vänta på uppgiften som returneras av RaiseConditionalEvent
för att bekräfta händelsen, dvs. det är inte nödvändigt att även anropa ConfirmEvents
.
Explicit synkronisering
Ibland är det önskvärt att se till att ett korn är helt ikapp den senaste versionen. Detta kan framtvingas genom att anropa:
await RefreshNow();
Detta gör två saker:
- Det bekräftar alla obekräftade händelser.
- Den läser in den senaste versionen från lagringen.