Potwierdzenia natychmiastowe i opóźnione
W tym artykule poznasz różnice między natychmiastowymi i opóźnionym potwierdzeniem.
Natychmiastowe potwierdzenie
W przypadku wielu aplikacji chcemy mieć pewność, że zdarzenia są natychmiast potwierdzane, tak aby utrwalone wersje nie były opóźnione za bieżącą wersją w pamięci i nie ryzykujemy utraty najnowszego stanu, jeśli ziarno powinno zakończyć się niepowodzeniem. Możemy to zagwarantować, postępując zgodnie z następującymi regułami:
- Upewnij się, że wszystkie RaiseEvent wywołania są używane ConfirmEvents przed zwróceniem metody ziarna.
- Przed zwróceniem metody ziarna upewnij się, że zadania zwracane przez RaiseConditionalEvent ukończenie.
- Unikaj ReentrantAttribute lub AlwaysInterleaveAttribute atrybutów, więc w danym momencie można przetworzyć tylko jedno wywołanie ziarna.
Jeśli będziemy przestrzegać tych reguł, oznacza to, że po wystąpieniu zdarzenia nie będzie można wykonać żadnego innego kodu ziarna do momentu zapisania zdarzenia do magazynu. W związku z tym nie można zaobserwować niespójności między wersją w pamięci a wersją w magazynie. Chociaż często jest to dokładnie to, czego chcemy, ma również pewne potencjalne wady.
Potencjalne wady
Jeśli połączenie z klastrem zdalnym lub magazynem zostanie tymczasowo przerwane, ziarno stanie się niedostępne: efektywnie ziarno nie może wykonać żadnego kodu, gdy utknie w oczekiwaniu na potwierdzenie zdarzeń, co może potrwać nieokreślony czas (protokół spójności dziennika będzie ponawiać próbę do czasu przywrócenia łączności magazynu).
W przypadku obsługi wielu aktualizacji pojedynczego wystąpienia ziarna potwierdzenie ich pojedynczo może stać się bardzo nieefektywne, na przykład powodując niską przepływność.
Potwierdzenie opóźnione
Aby zwiększyć dostępność i przepływność w sytuacjach wymienionych powyżej, ziarna mogą wykonać jedną lub obie z następujących czynności:
- Zezwalaj metodom ziarna na wywoływanie zdarzeń bez oczekiwania na potwierdzenie.
- Zezwalaj na ponowne wywołania, więc ziarno może nadal przetwarzać nowe wywołania, nawet jeśli poprzednie wywołania utknęły w oczekiwaniu na potwierdzenie.
Oznacza to, że kod ziarna może być wykonywany, gdy niektóre zdarzenia są nadal w trakcie potwierdzania. Interfejs JournaledGrain<TGrainState,TEventBase> API ma pewne konkretne przepisy, aby zapewnić deweloperom dokładną kontrolę nad sposobem radzenia sobie z niepotwierdzonym zdarzeniami, które są obecnie w locie.
Aby dowiedzieć się, jakie zdarzenia są obecnie niepotwierdzone, można zbadać następującą właściwość:
IEnumerable<EventType> UnconfirmedEvents { get; }
Ponadto, ponieważ stan zwracany przez JournaledGrain<TGrainState,TEventBase>.State właściwość nie obejmuje wpływu niepotwierdzonych zdarzeń, istnieje właściwość alternatywna
StateType TentativeState { get; }
Zwraca stan "wstępny" uzyskany z "State" przez zastosowanie wszystkich niepotwierdzonych zdarzeń. Stan wstępny jest zasadniczo "najlepszym zgadywaniem", co prawdopodobnie stanie się następnym potwierdzonym stanem po potwierdzeniu wszystkich niepotwierdzonych zdarzeń. Nie ma jednak gwarancji, że rzeczywiście będzie, ponieważ ziarno może zakończyć się niepowodzeniem lub ponieważ wydarzenia mogą ścigać się z innymi wydarzeniami i tracić, powodując ich anulowanie (jeśli są one warunkowe) lub pojawiają się na późniejszej pozycji w sekwencji niż oczekiwano (jeśli są bezwarunkowe).
Gwarancje współbieżności
Należy pamiętać, że Orleans gwarancje planowania opartego na kolei (współbieżność współpracy) są zawsze stosowane, nawet w przypadku ponownego uruchamiania lub opóźnionego potwierdzenia. Oznacza to, że mimo że kilka metod może być w toku, tylko jedna może być aktywnie uruchamiana — wszystkie inne utknęły w oczekiwaniu, więc nigdy nie ma żadnych prawdziwych wyścigów spowodowanych przez wątki równoległe.
W szczególności należy pamiętać, że:
- Właściwości State, TentativeState, Versioni UnconfirmedEvents mogą ulec zmianie podczas wykonywania metody.
- Ale takie zmiany mogą się zdarzyć tylko podczas utknięcia w oczekiwaniu.
Gwarancje te zakładają, że kod użytkownika pozostaje w zalecanej praktyce dotyczącej zadań i asynchronicznego/await (w szczególności nie używa zadań puli wątków lub używa ich tylko do kodu, który nie wywołuje funkcji ziarna i które są prawidłowo oczekiwane).