Spróbuj ponownie wykonać funkcje asynchroniczne

W tym dokumencie opisano, jak można zażądać, aby asynchroniczne (inne niż HTTPS) funkcje w tle ponawiały próbę w przypadku niepowodzenia.

Semantyka ponawiania próby

Cloud Functions gwarantuje co najmniej jednokrotne wykonanie funkcji sterowanej zdarzeniami dla każdego zdarzenia wyemitowanego przez źródło zdarzenia. Domyślnie, jeśli wywołanie funkcji zakończy się błędem, funkcja nie zostanie wywołana ponownie, a zdarzenie zostanie odrzucone. Jeśli włączysz ponowne próby dla funkcji sterowanej zdarzeniami, Cloud Functions będzie ponawiać nieudane wywołanie funkcji do czasu jej pomyślnego zakończenia lub wygaśnięcia okna ponawiania prób.

W przypadku funkcji drugiej generacji to okno ponownej próby wygasa po 24 godzinach. W przypadku funkcji 1. generacji wygasa po 7 dniach. Cloud Functions ponawia nowo utworzone funkcje sterowane zdarzeniami, korzystając ze strategii wykładniczego wycofywania, z rosnącym wycofywaniem wynoszącym od 10 do 600 sekund. Ta zasada jest stosowana do nowych funkcji przy pierwszym ich wdrożeniu. Nie jest ona stosowana z mocą wsteczną do istniejących funkcji, które zostały wdrożone przed wejściem w życie zmian opisanych w tej informacji o wersji , nawet jeśli funkcje zostaną ponownie wdrożone.

Jeśli ponowne próby nie są włączone dla funkcji, co jest ustawieniem domyślnym, funkcja zawsze zgłasza, że ​​została wykonana pomyślnie, a w jej dziennikach może pojawić się kod odpowiedzi 200 OK . Dzieje się tak nawet wtedy, gdy funkcja napotkała błąd. Aby było jasne, kiedy funkcja napotka błąd, pamiętaj o odpowiednim zgłoszeniu błędów .

Dlaczego funkcje sterowane zdarzeniami nie kończą się

W rzadkich przypadkach funkcja może zakończyć się przedwcześnie z powodu błędu wewnętrznego i domyślnie funkcja może zostać automatycznie ponowiona lub nie.

Bardziej typowo, funkcja sterowana zdarzeniami może nie zostać pomyślnie ukończona z powodu błędów zgłoszonych w samym kodzie funkcji. Przyczyny takiego stanu rzeczy mogą obejmować:

  • Funkcja zawiera błąd i środowisko wykonawcze zgłasza wyjątek.
  • Funkcja nie może osiągnąć punktu końcowego usługi lub podczas próby wykonania tej czynności upłynął limit czasu.
  • Funkcja celowo zgłasza wyjątek (na przykład, gdy walidacja parametru nie powiedzie się).
  • Funkcja Node.js zwraca odrzuconą obietnicę lub przekazuje wartość inną niż null do wywołania zwrotnego.

W każdym z powyższych przypadków funkcja domyślnie przestaje działać, a zdarzenie jest odrzucane. Aby ponowić próbę wykonania funkcji w przypadku wystąpienia błędu, można zmienić domyślną zasadę ponawiania , ustawiając właściwość „ponów próbę w przypadku niepowodzenia” . Powoduje to wielokrotne ponawianie zdarzenia, aż do pomyślnego zakończenia funkcji lub upłynięcia limitu czasu ponownej próby.

Włącz lub wyłącz ponowne próby

Skonfiguruj ponowne próby w konsoli GCP

Jeśli tworzysz nową funkcję:

  1. Na ekranie Utwórz funkcję wybierz opcję Dodaj wyzwalacz i wybierz typ zdarzenia, które będzie wyzwalaczem funkcji.
  2. W panelu wyzwalacza Eventarc zaznacz pole wyboru Ponów próbę w przypadku niepowodzenia , aby włączyć ponowne próby.

Jeśli aktualizujesz istniejącą funkcję:

  1. Na stronie Przegląd funkcji Cloud kliknij nazwę aktualizowanej funkcji, aby otworzyć ekran szczegółów funkcji , a następnie wybierz opcję Edytuj z paska menu, aby wyświetlić panele wyzwalaczy HTTPS i Eventarc .
  2. W panelu wyzwalacza Eventarc kliknij ikonę edycji , aby edytować ustawienia wyzwalacza.
  3. W panelu wyzwalacza Eventarc zaznacz lub wyczyść pole wyboru Ponów próbę w przypadku niepowodzenia , aby włączyć lub wyłączyć ponowne próby.

Skonfiguruj ponowne próby z poziomu kodu funkcji

Dzięki Cloud Functions dla Firebase możesz włączyć ponowne próby w kodzie funkcji. Aby to zrobić dla funkcji tła, takiej jak functions.foo.onBar(myHandler); , użyj runWith i skonfiguruj politykę awarii:

functions.runWith({failurePolicy: true}).foo.onBar(myHandler);

Ustawienie true , jak pokazano, konfiguruje funkcję do ponownej próby w przypadku niepowodzenia.

Najlepsze praktyki

W tej sekcji opisano najlepsze praktyki dotyczące korzystania z ponownych prób.

Użyj ponownej próby, aby obsłużyć błędy przejściowe

Ponieważ funkcja jest ponawiana w sposób ciągły aż do pomyślnego wykonania, należy wyeliminować z kodu trwałe błędy, takie jak błędy, poprzez testowanie przed włączeniem ponownych prób. Ponownych prób najlepiej używać do obsługi sporadycznych/przejściowych błędów, które mają duże prawdopodobieństwo rozwiązania po ponowieniu, takich jak niestabilny punkt końcowy usługi lub przekroczenie limitu czasu.

Ustaw warunek końcowy, aby uniknąć nieskończonych pętli ponawiania prób

Najlepszą praktyką jest ochrona funkcji przed ciągłym zapętlaniem podczas korzystania z ponownych prób. Można to zrobić, dołączając dobrze zdefiniowany warunek końcowy, zanim funkcja rozpocznie przetwarzanie. Należy pamiętać, że ta technika działa tylko wtedy, gdy funkcja uruchomi się pomyślnie i jest w stanie ocenić warunek końcowy.

Prostym, ale skutecznym podejściem jest odrzucanie zdarzeń ze znacznikami czasu starszymi niż określony czas. Pomaga to uniknąć nadmiernego wykonania, gdy awarie są trwałe lub trwają dłużej niż oczekiwano.

Na przykład ten fragment kodu odrzuca wszystkie zdarzenia starsze niż 10 sekund:

const eventAgeMs = Date.now() - Date.parse(event.timestamp);
const eventMaxAgeMs = 10000;
if (eventAgeMs > eventMaxAgeMs) {
  console.log(`Dropping event ${event} with age[ms]: ${eventAgeMs}`);
  callback();
  return;
}

Użyj catch z obietnicami

Jeśli funkcja ma włączone ponowne próby, każdy nieobsługiwany błąd spowoduje ponowną próbę. Upewnij się, że kod przechwytuje wszelkie błędy, które nie powinny skutkować ponowną próbą.

Oto przykład tego, co powinieneś zrobić:

return doFooAsync().catch((err) => {
    if (isFatal(err)) {
        console.error(`Fatal error ${err}`);
    }
    return Promise.reject(err);
});

Ustaw idempotentne funkcje sterowane zdarzeniami, które można ponawiać

Funkcje sterowane zdarzeniami, które można ponowić, muszą być idempotentne. Oto kilka ogólnych wskazówek, jak uczynić taką funkcję idempotentną:

  • Wiele zewnętrznych interfejsów API (takich jak Stripe) umożliwia podanie klucza idempotencji jako parametru. Jeśli korzystasz z takiego API, powinieneś użyć identyfikatora zdarzenia jako klucza idempotencji.
  • Idempotencja działa dobrze w przypadku dostarczenia co najmniej raz, ponieważ sprawia, że ​​ponowna próba jest bezpieczna. Zatem ogólną najlepszą praktyką pisania niezawodnego kodu jest łączenie idempotencji z ponownymi próbami.
  • Upewnij się, że Twój kod jest wewnętrznie idempotentny. Na przykład:
    • Upewnij się, że mutacje mogą wystąpić więcej niż raz bez zmiany wyniku.
    • Zapytaj o stan bazy danych w transakcji przed mutacją stanu.
    • Upewnij się, że wszystkie skutki uboczne same w sobie są idempotentne.
  • Nałóż kontrolę transakcyjną poza funkcją, niezależnie od kodu. Na przykład utrwal gdzieś stan rejestrujący, że dany identyfikator zdarzenia został już przetworzony.
  • Radź sobie ze zduplikowanymi wywołaniami funkcji poza pasmem. Na przykład użyj osobnego procesu czyszczenia, który czyści po zduplikowanych wywołaniach funkcji.

Skonfiguruj zasady ponawiania

W zależności od potrzeb Twojej Funkcji Cloud możesz bezpośrednio skonfigurować zasady ponawiania. Umożliwi to skonfigurowanie dowolnej kombinacji następujących elementów:

  • Skróć okno ponownej próby z 7 dni do zaledwie 10 minut.
  • Zmień minimalny i maksymalny czas wycofywania dla strategii ponawiania wykładniczego wycofywania.
  • Zmień strategię ponawiania prób, aby ponowić próbę natychmiast.
  • Skonfiguruj temat niedostarczonych wiadomości .
  • Ustaw maksymalną i minimalną liczbę prób doręczenia.

Aby skonfigurować zasadę ponawiania:

  1. Napisz funkcję HTTP.
  2. Użyj interfejsu API Pub/Sub, aby utworzyć subskrypcję Pub/Sub, określając adres URL funkcji jako cel.

Więcej informacji na temat bezpośredniej konfiguracji Pub/Sub można znaleźć w dokumentacji Pub/Sub dotyczącej obsługi błędów .