W tym dokumencie opisano, jak można zażądać asynchronicznych funkcji w tle (innych niż HTTPS) w celu ponowienia próby w przypadku niepowodzenia.
Semantyka ponawiania próby
Cloud Functions gwarantuje co najmniej jednokrotne wykonanie funkcji sterowanej zdarzeniami dla każdego zdarzenia emitowanego przez źródło zdarzenia. Jednak domyślnie, jeśli wywołanie funkcji zakończy się błędem, funkcja nie zostanie wywołana ponownie, a zdarzenie zostanie odrzucone. Gdy włączysz ponawianie prób w funkcji sterowanej zdarzeniami, Cloud Functions będzie ponawiać nieudane wywołania funkcji, dopóki nie zakończy się pomyślnie lub wygaśnie okno ponawiania. W przypadku funkcji drugiej generacji okno ponawiania próby wygasa po 24 godzinach. W przypadku funkcji 1. generacji wygasa po 7 dniach. Nowo utworzone funkcje sterowane zdarzeniami będą ponawiać próbę przy użyciu wykładniczej strategii wycofywania, z minimalnym wycofywaniem wynoszącym 10 sekund i maksymalnym wycofywaniem wynoszącym 600 sekund lub dziesięć minut. Ta zasada jest stosowana do nowych funkcji przy pierwszym ich wdrożeniu. Nie stosuje się go wstecz do istniejących funkcji, które zostały wdrożone po raz pierwszy przed wejściem w życie zmian opisanych w tej informacji o wersji , nawet jeśli ponownie wdrożysz te funkcje.
Gdy ponawianie prób nie jest włączone dla funkcji, co jest ustawieniem domyślnym, funkcja zawsze zgłasza pomyślne wykonanie, aw jej dziennikach może pojawić się 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łaszaniu 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 zakończyć się niepowodzeniem z powodu błędów zgłoszonych w samym kodzie funkcji. Oto niektóre przyczyny, dla których może się to zdarzyć:
- Funkcja zawiera błąd, a środowisko uruchomieniowe zgłasza wyjątek.
- Funkcja nie może dotrzeć do punktu końcowego usługi lub upłynął limit czasu podczas próby osiągnięcia punktu końcowego.
- Funkcja celowo zgłasza wyjątek (na przykład, gdy walidacja parametru nie powiedzie się).
- Gdy funkcje napisane w Node.js zwracają odrzuconą obietnicę lub przekazują 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. Jeśli chcesz ponowić próbę użycia funkcji, gdy wystąpi błąd, możesz zmienić domyślne zasady ponawiania , ustawiając właściwość „ponów próbę w przypadku niepowodzenia” . Powoduje to wielokrotne ponawianie zdarzenia przez maksymalnie wiele dni, aż funkcja zakończy się pomyślnie.
Włączanie i wyłączanie ponawiania prób
Korzystanie z konsoli GCP
Możesz włączyć lub wyłączyć ponowne próby w konsoli GCP w następujący sposób:
Przejdź do strony Przegląd funkcji Cloud w konsoli Cloud Platform.
Kliknij Utwórz funkcję . Możesz też kliknąć istniejącą funkcję, aby przejść do jej strony szczegółów i kliknąć Edytuj .
Wypełnij wymagane pola dla swojej funkcji.
Upewnij się, że pole Wyzwalacz jest ustawione na typ wyzwalacza oparty na zdarzeniu, taki jak Cloud Pub/Sub lub Cloud Storage.
Rozwiń ustawienia zaawansowane, klikając Więcej .
Zaznacz lub odznacz pole wyboru Ponów próbę w przypadku niepowodzenia .
W kodzie funkcji
Dzięki Cloud Functions dla Firebase możesz włączyć ponawianie prób w kodzie dla funkcji. Aby to zrobić dla funkcji działającej w tle, 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ę, aby ponawiała próbę w przypadku niepowodzenia.
Najlepsze praktyki
W tej sekcji opisano najlepsze rozwiązania dotyczące używania ponownych prób.
Użyj ponawiania próby, aby obsłużyć przejściowe błędy
Ponieważ twoja funkcja jest ponawiana w sposób ciągły aż do pomyślnego wykonania, stałe błędy, takie jak błędy, powinny zostać wyeliminowane z twojego kodu 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 ponownych próbach, takich jak niestabilny punkt końcowy usługi lub przekroczenie limitu czasu.
Ustaw warunek końcowy, aby uniknąć nieskończonych pętli ponawiania
Najlepszą praktyką jest ochrona funkcji przed ciągłym zapętlaniem podczas korzystania z ponownych prób. Możesz to zrobić, dołączając dobrze zdefiniowany warunek końcowy, zanim funkcja rozpocznie przetwarzanie. Zauważ, że ta technika działa tylko wtedy, gdy funkcja uruchamia się pomyślnie i jest w stanie ocenić warunek końcowy.
Prostym, ale skutecznym podejściem jest odrzucanie zdarzeń z sygnaturami czasowymi starszymi niż określony czas. Pomaga to uniknąć nadmiernych egzekucji, 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 Twoja funkcja ma włączone ponawianie prób, każdy nieobsługiwany błąd spowoduje ponowienie próby. Upewnij się, że Twój kod przechwytuje wszelkie błędy, które nie powinny skutkować ponowieniem.
Oto przykład tego, co powinieneś zrobić:
return doFooAsync().catch((err) => {
if (isFatal(err)) {
console.error(`Fatal error ${err}`);
}
return Promise.reject(err);
});
Zapewnij idempotentne funkcje sterowane zdarzeniami, które można ponawiać
Funkcje sterowane zdarzeniami, które mogą być ponawiane, muszą być idempotentne. Oto kilka ogólnych wskazówek, jak sprawić, by taka funkcja była idempotentna:
- Wiele zewnętrznych interfejsów API (takich jak Stripe) umożliwia podanie klucza idempotencji jako parametru. Jeśli używasz takiego interfejsu API, powinieneś użyć identyfikatora zdarzenia jako klucza idempotencji.
- Idempotentność działa dobrze w przypadku dostarczania co najmniej raz, ponieważ umożliwia bezpieczne ponowienie próby. Tak więc 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ż jeden raz bez zmiany wyniku.
- Zapytanie o stan bazy danych w transakcji przed mutacją stanu.
- Upewnij się, że wszystkie efekty uboczne są idempotentne.
- Narzuć kontrolę transakcyjną poza funkcją, niezależnie od kodu. Na przykład utrzymuj stan gdzieś, rejestrując, że dany identyfikator zdarzenia został już przetworzony.
- Radzenie sobie z powielonymi wywołaniami funkcji poza pasmem. Na przykład mieć oddzielny proces czyszczenia, który czyści po zduplikowanych wywołaniach funkcji.
Skonfiguruj zasady ponawiania
W zależności od potrzeb Twojej funkcji w chmurze możesz chcieć bezpośrednio skonfigurować zasady ponawiania. Umożliwiłoby 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 wycofywania wykładniczego.
- Zmień strategię ponawiania, aby spróbować natychmiast.
- Skonfiguruj temat niedostarczonych wiadomości .
- Ustaw maksymalną i minimalną liczbę prób dostarczenia.
Aby skonfigurować zasady ponawiania:
- Napisz funkcję HTTP.
- Użyj interfejsu API Pub/Sub, aby utworzyć subskrypcję Pub/Sub, określając adres URL funkcji jako cel.
Zobacz dokumentację Pub/Sub dotyczącą obsługi błędów, aby uzyskać więcej informacji na temat bezpośredniego konfigurowania Pub/Sub.