Sdílet prostřednictvím


Základy deníkuGrain

Žurná zrnka jsou odvozena z JournaledGrain<TGrainState,TEventBase>, s následujícími parametry typu:

  • Představuje TGrainState stav agregace. Musí to být třída s veřejným výchozím konstruktorem.
  • TEventBase je běžný supertyp pro všechny události, které mohou být vyvolány pro toto agregační interval, a může být libovolnou třídou nebo rozhraním.

Všechny objekty stavu a událostí by měly být serializovatelné (protože zprostředkovatelé konzistence protokolu mohou potřebovat je zachovat a/nebo je odesílat ve zprávách oznámení).

Pro zrní, jejichž události jsou POCOs (prosté staré objekty jazyka C#), JournaledGrain<TGrainState> lze použít jako zkratku pro JournaledGrain<TGrainState,TEventBase>.

Čtení stavu zrnitosti

Pokud chcete přečíst aktuální stav agregačního intervalu a určit jeho číslo verze, má JournaledGrain vlastnosti.

GrainState State { get; }
int Version { get; }

Číslo verze se vždy rovná celkovému počtu potvrzených událostí a stav je výsledkem použití všech potvrzených událostí na počáteční stav. Počáteční stav, který má verzi 0 (protože na ni nebyly použity žádné události), je určen výchozím konstruktorem třídy GrainState.

Důležité: Aplikace by nikdy neměla přímo upravovat objekt vrácený State. Je určen jen pro čtení. Místo toho, když aplikace chce změnit stav, musí to udělat nepřímo vyvoláním událostí.

Vyvolání událostí

Vyvolání událostí se provádí voláním RaiseEvent funkce. Například zrnité znázornění chatu může vyvolat PostedEvent upozornění, že uživatel odeslal příspěvek:

RaiseEvent(new PostedEvent()
{
    Guid = guid,
    User = user,
    Text = text,
    Timestamp = DateTime.UtcNow
});

Všimněte si, že RaiseEvent spustí zápis do úložiště, ale nečeká na dokončení zápisu. U mnoha aplikací je důležité počkat, až potvrdíme, že událost byla zachována. V takovém případě vždy budeme pokračovat čekáním na ConfirmEvents:

RaiseEvent(new DepositTransaction()
{
    DepositAmount = amount,
    Description = description
});
await ConfirmEvents();

Všimněte si, že i když explicitně nezavoláte ConfirmEvents, události se nakonec potvrdí – dojde k tomu automaticky na pozadí.

Metody přechodu stavu

Modul runtime aktualizuje stav agregační intervalu automaticky při každém vyvolání událostí. Po vyvolání události není nutné, aby aplikace explicitně aktualizovala stav. Aplikace však stále musí poskytnout kód, který určuje , jak aktualizovat stav v reakci na událost. To lze provést dvěma způsoby.

a) Třída GrainState může implementovat jednu nebo více Apply metod v objektu StateType. Obvykle by jedna vytvořila více přetížení a pro typ modulu runtime události se vybere nejbližší shoda:

class GrainState
{
    Apply(E1 @event)
    {
        // code that updates the state
    }

    Apply(E2 @event)
    {
        // code that updates the state
    }
}

b) Agregační interval může přepsat TransitionState funkci:

protected override void TransitionState(
    State state, EventType @event)
{
   // code that updates the state
}

U přechodových metod se předpokládá, že nemají jiné vedlejší účinky než úpravu objektu stavu a měly by být deterministické (jinak jsou efekty nepředvídatelné). Pokud kód přechodu vyvolá výjimku, tato výjimka se zachytí a zahrne do upozornění v Orleans protokolu vydaném poskytovatelem konzistence protokolu.

Když modul runtime volá metody přechodu, závisí na zvoleném poskytovateli konzistence protokolu a jeho konfiguraci. Aplikace by se neměly spoléhat na konkrétní časování, s výjimkou případů, kdy je výslovně zaručeno poskytovatelem konzistence protokolu.

Někteří zprostředkovatelé, například Orleans.EventSourcing.LogStorage zprostředkovatel konzistence protokolu, přehrají posloupnost událostí při každém načtení agregačního intervalu. Proto, pokud mohou být objekty událostí stále správně deserializovány z úložiště, je možné radikálně upravit GrainState třídu a přechodové metody. U jiných poskytovatelů, jako Orleans.EventSourcing.StateStorage je například zprostředkovatel konzistence protokolu, je však zachován pouze GrainState objekt, takže vývojáři musí zajistit, aby se při čtení z úložiště správně deserializoval.

Vyvolání více událostí

Před voláním ConfirmEventsje možné provést více voláníRaiseEvent:

RaiseEvent(e1);
RaiseEvent(e2);
await ConfirmEvents();

Pravděpodobně to ale způsobí dva následné přístupy k úložišti a dojde k riziku, že se agregační interval po zápisu pouze první události nezdaří. Proto je obvykle lepší vyvolat více událostí najednou pomocí

RaiseEvents(IEnumerable<EventType> events)

To zaručuje, že se daná posloupnost událostí zapíše do úložiště atomicky. Všimněte si, že vzhledem k tomu, že číslo verze vždy odpovídá délce sekvence událostí, zvýšením více událostí se číslo verze zvýší o vícekrát najednou.

Načtení sekvence událostí

Následující metoda ze základní JournaledGrain třídy umožňuje aplikaci načíst zadaný segment sekvence všech potvrzených událostí:

Task<IReadOnlyList<EventType>> RetrieveConfirmedEvents(
    int fromVersion,
    int toVersion);

Všichni zprostředkovatelé konzistence protokolů ho ale nepodporují. Pokud není podporovaný nebo pokud zadaný segment sekvence již není k dispozici, NotSupportedException vyvolá se vyvolá.

Pokud chcete načíst všechny události až do nejnovější potvrzené verze, zavolá se jedna.

await RetrieveConfirmedEvents(0, Version);

Lze načíst pouze potvrzené události: Výjimka je vyvolán, pokud toVersion je větší než aktuální hodnota vlastnosti Version.

Vzhledem k tomu, že potvrzené události se nikdy nemění, neexistují žádné závody, které by se neměly starat, ani v přítomnosti více instancí nebo zpožděných potvrzení. V takových situacích však může být hodnota vlastnosti Version větší o čas await , RetrieveConfirmedEvents než je volána, takže může být vhodné uložit jeho hodnotu v proměnné. Viz také část o zárukách souběžnosti.