Udostępnij za pośrednictwem


Powiadomienia dotyczące usług Reliable Services

Powiadomienia umożliwiają klientom śledzenie zmian wprowadzonych w obiekcie, który cię interesuje. Dwa typy obiektów obsługują powiadomienia: Reliable State Manager i Reliable Dictionary.

Typowe przyczyny korzystania z powiadomień to:

  • Tworzenie zmaterializowanych widoków, takich jak indeksy pomocnicze lub zagregowane przefiltrowane widoki stanu repliki. Przykładem jest posortowany indeks wszystkich kluczy w słowniku Reliable Dictionary.
  • Wysyłanie danych monitorowania, takich jak liczba użytkowników dodanych w ciągu ostatniej godziny.

Powiadomienia są wyzwalane w ramach stosowania operacji. W repliki podstawowej operacje są stosowane po potwierdzeniu kworum jako części transaction.CommitAsync() lub this.StateManager.GetOrAddAsync(). W replikach pomocniczych operacje są stosowane podczas przetwarzania danych kolejki replikacji. W związku z tym powiadomienia powinny być obsługiwane tak szybko, jak to możliwe, a zdarzenia synchroniczne nie powinny obejmować żadnych kosztownych operacji. W przeciwnym razie może to negatywnie wpłynąć na czas przetwarzania transakcji, a także kompilacje repliki.

Powiadomienia usługi Reliable State Manager

Usługa Reliable State Manager udostępnia powiadomienia dotyczące następujących zdarzeń:

  • Transakcja
    • Zatwierdzenie
  • Menedżer stanu
    • Ponowne kompilowanie
    • Dodawanie niezawodnego stanu
    • Usuwanie niezawodnego stanu

Reliable State Manager śledzi bieżące transakcje wlotowe. Jedyną zmianą stanu transakcji, która powoduje wyzwolenie powiadomienia, jest zatwierdzanie transakcji.

Usługa Reliable State Manager utrzymuje kolekcję niezawodnych stanów, takich jak Reliable Dictionary i Reliable Queue. Funkcja Reliable State Manager uruchamia powiadomienia, gdy ta kolekcja ulegnie zmianie: zostanie dodany lub usunięty niezawodny stan albo cała kolekcja zostanie ponownie skompilowana. Kolekcja Reliable State Manager jest przebudowana w trzech przypadkach:

  • Odzyskiwanie: po uruchomieniu repliki odzyskuje poprzedni stan z dysku. Na końcu odzyskiwania używa elementu NotifyStateManagerChangedEventArgs do wyzwolenia zdarzenia zawierającego zestaw odzyskanych niezawodnych stanów.
  • Pełna kopia: zanim replika będzie mogła dołączyć do zestawu konfiguracji, musi zostać skompilowana. Czasami wymaga to pełnej kopii stanu menedżera niezawodnego stanu z repliki podstawowej do zastosowania do bezczynnej repliki pomocniczej. Funkcja Reliable State Manager w replice pomocniczej używa elementu NotifyStateManagerChangedEventArgs w celu wyzwolenia zdarzenia zawierającego zestaw niezawodnych stanów uzyskanych z repliki podstawowej.
  • Przywracanie: w scenariuszach odzyskiwania po awarii stan repliki można przywrócić z kopii zapasowej za pomocą funkcji RestoreAsync. W takich przypadkach funkcja Reliable State Manager w replice podstawowej używa elementu NotifyStateManagerChangedEventArgs w celu wyzwolenia zdarzenia zawierającego zestaw niezawodnych stanów przywróconych z kopii zapasowej.

Aby zarejestrować powiadomienia o transakcji i/lub powiadomienia menedżera stanu, należy zarejestrować się w zdarzeniach TransactionChanged lub StateManagerChanged w usłudze Reliable State Manager. Typowym miejscem rejestrowania się w tych programach obsługi zdarzeń jest konstruktor usługi stanowej. Podczas rejestrowania w konstruktorze nie zostanie pominięte żadne powiadomienie spowodowane przez zmianę w okresie istnienia elementu IReliableStateManager.

public MyService(StatefulServiceContext context)
    : base(MyService.EndpointName, context, CreateReliableStateManager(context))
{
    this.StateManager.TransactionChanged += this.OnTransactionChangedHandler;
    this.StateManager.StateManagerChanged += this.OnStateManagerChangedHandler;
}

Procedura obsługi zdarzeń TransactionChanged używa elementu NotifyTransactionChangedEventArgs , aby podać szczegółowe informacje o zdarzeniu. Zawiera właściwość akcji (na przykład NotifyTransactionChangedAction.Commit), która określa typ zmiany. Zawiera również właściwość transakcji, która zawiera odwołanie do transakcji, która uległa zmianie.

Uwaga

Obecnie zdarzenia TransactionChanged są zgłaszane tylko wtedy, gdy transakcja zostanie zatwierdzona. Akcja jest następnie równa NotifyTransactionChangedAction.Commit. Jednak w przyszłości zdarzenia mogą być zgłaszane dla innych typów zmian stanu transakcji. Zalecamy sprawdzenie akcji i przetworzenie zdarzenia tylko wtedy, gdy jest to oczekiwane zdarzenie.

Poniżej przedstawiono przykładową procedurę obsługi zdarzeń TransactionChanged .

private void OnTransactionChangedHandler(object sender, NotifyTransactionChangedEventArgs e)
{
    if (e.Action == NotifyTransactionChangedAction.Commit)
    {
        this.lastCommitLsn = e.Transaction.CommitSequenceNumber;
        this.lastTransactionId = e.Transaction.TransactionId;

        this.lastCommittedTransactionList.Add(e.Transaction.TransactionId);
    }
}

Procedura obsługi zdarzeń StateManagerChanged używa elementu NotifyStateManagerChangedEventArgs , aby podać szczegółowe informacje o zdarzeniu. NotifyStateManagerChangedEventArgs ma dwie podklasy : NotifyStateManagerRebuildEventArgs i NotifyStateManagerSingleEntityChangedEventArgs. Właściwość akcji w elemencie NotifyStateManagerChangedEventArgs służy do rzutowania elementu NotifyStateManagerChangedEventArgs na poprawną podklasę:

  • NotifyStateManagerChangedAction.Rebuild: NotifyStateManagerRebuildEventArgs
  • NotifyStateManagerChangedAction.Add i NotifyStateManagerChangedAction.Remove: NotifyStateManagerSingleEntityChangedEventArgs

Poniżej przedstawiono przykładową procedurę obsługi powiadomień StateManagerChanged .

public void OnStateManagerChangedHandler(object sender, NotifyStateManagerChangedEventArgs e)
{
    if (e.Action == NotifyStateManagerChangedAction.Rebuild)
    {
        this.ProcessStateManagerRebuildNotification(e);

        return;
    }

    this.ProcessStateManagerSingleEntityNotification(e);
}

Powiadomienia dotyczące niezawodnego słownika

Usługa Reliable Dictionary udostępnia powiadomienia dotyczące następujących zdarzeń:

  • Ponowna kompilacja: wywoływana, gdy element ReliableDictionary został odzyskany do stanu odzyskiwania pośredniego z odzyskanego lub skopiowanego stanu lokalnego lub kopii zapasowej. Rekord transakcji od momentu utworzenia tego stanu odzyskiwania zostanie zastosowany przed zakończeniem ponownego kompilowania. Zastosowanie tego rekordu zapewni jasne, dodawanie, aktualizowanie i/lub usuwanie powiadomień.
  • Wyczyść: wywoływana, gdy stan reliableDictionary został wyczyszczone za pomocą metody ClearAsync .
  • Dodaj: wywoływana, gdy element został dodany do elementu ReliableDictionary.
  • Aktualizacja: wywoływana po zaktualizowaniu elementu w elemencie IReliableDictionary .
  • Usuń: wywoływana, gdy element w elemencie IReliableDictionary został usunięty.

Aby uzyskać powiadomienia usługi Reliable Dictionary, należy zarejestrować się w programie obsługi zdarzeń DictionaryChanged w usłudze IReliableDictionary. Typowym miejscem rejestrowania się w tych programach obsługi zdarzeń jest dodanie powiadomienia ReliableStateManager.StateManagerChanged . Rejestracja podczas dodawania elementu IReliableDictionary do elementu IReliableStateManager gwarantuje, że nie przegapisz żadnych powiadomień.

private void ProcessStateManagerSingleEntityNotification(NotifyStateManagerChangedEventArgs e)
{
    var operation = e as NotifyStateManagerSingleEntityChangedEventArgs;

    if (operation.Action == NotifyStateManagerChangedAction.Add)
    {
        if (operation.ReliableState is IReliableDictionary<TKey, TValue>)
        {
            var dictionary = (IReliableDictionary<TKey, TValue>)operation.ReliableState;
            dictionary.RebuildNotificationAsyncCallback = this.OnDictionaryRebuildNotificationHandlerAsync;
            dictionary.DictionaryChanged += this.OnDictionaryChangedHandler;
        }
    }
}

Uwaga

ProcessStateManagerSingleEntityNotification to przykładowa metoda wywołania poprzedniego przykładu OnStateManagerChangedHandler .

Powyższy kod ustawia interfejs IReliableNotificationAsyncCallback wraz ze słownikiemChanged. Ponieważ element NotifyDictionaryRebuildEventArgs zawiera interfejs IAsyncEnumerable — który musi zostać wyliczony asynchronicznie — powiadomienia ponownej kompilacji są wyzwalane za pomocą polecenia RebuildNotificationAsyncCallback zamiast OnDictionaryChangedHandler.

public async Task OnDictionaryRebuildNotificationHandlerAsync(
    IReliableDictionary<TKey, TValue> origin,
    NotifyDictionaryRebuildEventArgs<TKey, TValue> rebuildNotification)
{
    this.secondaryIndex.Clear();

    var enumerator = e.State.GetAsyncEnumerator();
    while (await enumerator.MoveNextAsync(CancellationToken.None))
    {
        this.secondaryIndex.Add(enumerator.Current.Key, enumerator.Current.Value);
    }
}

Uwaga

W poprzednim kodzie, w ramach przetwarzania powiadomienia ponownego kompilowania, najpierw zachowany stan zagregowany jest czyszczone. Ponieważ niezawodna kolekcja jest odbudowywana z nowym stanem, wszystkie poprzednie powiadomienia są nieistotne.

Program obsługi zdarzeń DictionaryChanged używa elementu NotifyDictionaryChangedEventArgs , aby podać szczegółowe informacje o zdarzeniu. NotifyDictionaryChangedEventArgs ma pięć podklas . Użyj właściwości akcji w elemencie NotifyDictionaryChangedEventArgs, aby rzutować właściwość NotifyDictionaryChangedEventArgs na poprawną podklasę:

  • NotifyDictionaryChangedAction.Rebuild: NotifyDictionaryRebuildEventArgs
  • NotifyDictionaryChangedAction.Clear: NotifyDictionaryClearEventArgs
  • NotifyDictionaryChangedAction.Add: NotifyDictionaryItemAddedEventArgs
  • NotifyDictionaryChangedAction.Update: NotifyDictionaryItemUpdatedEventArgs
  • NotifyDictionaryChangedAction.Remove: NotifyDictionaryItemRemovedEventArgs
public void OnDictionaryChangedHandler(object sender, NotifyDictionaryChangedEventArgs<TKey, TValue> e)
{
    switch (e.Action)
    {
        case NotifyDictionaryChangedAction.Clear:
            var clearEvent = e as NotifyDictionaryClearEventArgs<TKey, TValue>;
            this.ProcessClearNotification(clearEvent);
            return;

        case NotifyDictionaryChangedAction.Add:
            var addEvent = e as NotifyDictionaryItemAddedEventArgs<TKey, TValue>;
            this.ProcessAddNotification(addEvent);
            return;

        case NotifyDictionaryChangedAction.Update:
            var updateEvent = e as NotifyDictionaryItemUpdatedEventArgs<TKey, TValue>;
            this.ProcessUpdateNotification(updateEvent);
            return;

        case NotifyDictionaryChangedAction.Remove:
            var deleteEvent = e as NotifyDictionaryItemRemovedEventArgs<TKey, TValue>;
            this.ProcessRemoveNotification(deleteEvent);
            return;

        default:
            break;
    }
}

Zalecenia

  • Wykonaj zdarzenia powiadomień tak szybko, jak to możliwe.
  • Nie wykonuj żadnych kosztownych operacji (na przykład operacji we/wy) w ramach zdarzeń synchronicznych.
  • Przed przetworzeniem zdarzenia sprawdź typ akcji. Nowe typy akcji mogą zostać dodane w przyszłości.

Oto kilka kwestii, o których warto pamiętać:

  • Powiadomienia są wyzwalane w ramach wykonywania operacji. Na przykład powiadomienie o przywróceniu jest uruchamiane jako krok operacji przywracania. Przywracanie nie będzie kontynuowane do momentu przetworzenia zdarzenia powiadomienia.
  • Ponieważ powiadomienia są wyzwalane w ramach operacji stosowania, klienci widzą tylko powiadomienia dotyczące operacji zatwierdzonych lokalnie. Ze względu na to, że operacje są gwarantowane tylko lokalnie (innymi słowy, zarejestrowane), mogą one lub nie mogą zostać cofnięte w przyszłości.
  • Na ścieżce ponownej instalacji zostanie wyzwolone pojedyncze powiadomienie dla każdej zastosowanej operacji. Oznacza to, że jeśli transakcja T1 zawiera metody Create(X), Delete(X) i Create(X), otrzymasz jedno powiadomienie o utworzeniu elementu X, jeden dla usunięcia, a drugi do utworzenia w tej kolejności.
  • W przypadku transakcji zawierających wiele operacji operacje są stosowane w kolejności, w jakiej zostały odebrane w repliki podstawowej od użytkownika.
  • W ramach przetwarzania fałszywych postępów niektóre operacje mogą zostać cofnięte w replikach pomocniczych. Powiadomienia są zgłaszane dla takich operacji cofania, cofanie stanu repliki z powrotem do stabilnego punktu. Jedną z ważnych różnic w powiadomieniach cofania jest to, że zdarzenia, które mają zduplikowane klucze, są agregowane. Jeśli na przykład transakcja T1 jest cofniętą, zobaczysz pojedyncze powiadomienie do polecenia Delete(X).

Następne kroki

Znane problemy

  • W określonych sytuacjach niektóre powiadomienia dotyczące transakcji mogą zostać pominięte podczas ponownej kompilacji. W takim przypadku poprawna wartość jest nadal obecna i nadal może być odczytywana lub iteracja; brakuje tylko powiadomienia. Aby odzyskać stan w pamięci, niezawodne kolekcje używają dziennika z wyprzedzeniem zapisu, który jest okresowo skondensowany do pliku punktu kontrolnego. Podczas przywracania najpierw stan podstawowy jest ładowany z plików punktów kontrolnych, co wyzwala ponowne uruchomienie powiadomienia. Następnie są stosowane transakcje zapisane w dzienniku, z których każda wyzwala jest własna, jasna, dodaj, zaktualizuj lub usuń powiadomienie. Ten problem może wynikać z stanu wyścigu, w którym nowy punkt kontrolny jest wykonywany szybko po przywróceniu. Jeśli punkt kontrolny zostanie ukończony przed zastosowaniem dziennika, stan w pamięci zostanie ustawiony na stan nowego punktu kontrolnego. Chociaż powoduje to prawidłowy stan, oznacza to, że transakcje w dzienniku, które nie zostały jeszcze zastosowane, nie będą wysyłać powiadomień.