Ponów próbę użycia funkcji asynchronicznych

Z tego dokumentu dowiesz się, jak możesz poprosić o powtórzenie nieudanej funkcji tlenowej (nie korzystającej z protokołu HTTPS).

Dlaczego funkcje reagujące na zdarzenia nie są wykonywane

W rzadkich przypadkach funkcja może zostać przerwana z powodu błędu wewnętrznego. Domyślnie funkcja może lub nie może zostać automatycznie wykonana ponownie.

Zwykle funkcja wywoływana przez zdarzenie może się nie uruchomić z powodu błędów w samym kodzie funkcji. Oto możliwe przyczyny:

  • Funkcja zawiera błąd, a czas wykonywania zgłasza wyjątek.
  • Funkcja nie może dotrzeć do punktu końcowego usługi lub upłynie limit czasu podczas próby wykonania tej operacji.
  • Funkcja celowo zgłasza wyjątek (na przykład, gdy parametr nie przechodzi walidacji).
  • Funkcja Node.js zwraca odrzucone obietnice lub przekazuje do funkcji wywołującej wartość inną niż null.

W każdym z tych przypadków funkcja przestanie się wykonywać i zwróci błąd. Wyzwalacze zdarzeń, które generują wiadomości, mają zasady ponawiania, które możesz dostosować do potrzeb swojej funkcji.

Semantyka ponownej próby

Cloud Functions zapewnia co najmniej jednokrotne wykonanie funkcji sterowanej zdarzeniami w przypadku każdego zdarzenia wyemitowanego przez źródło zdarzeń. Sposób konfigurowania prób ponownego wykonania zależy od tego, jak została utworzona funkcja:

  • Funkcje utworzone w konsoli Google Cloud lub za pomocą interfejsu Cloud RunAdmin API wymagają osobnego tworzenia i zarządzania wyzwalaczami zdarzeń. Wyzwalacze mają domyślne zachowania ponownego próbowania, które możesz dostosować do potrzeb swojej funkcji.
  • Funkcje utworzone za pomocą interfejsu Cloud Functions API w wersji 2 będą domyślnie tworzyć niezbędne stymulatory zdarzeń, na przykład Pub/Sub tematy lub Eventarc stymulatory. Domyślnie w przypadku tych wyzwalaczy ponowne próby są wyłączone. Można je ponownie włączyć za pomocą interfejsu Cloud Functions API w wersji 2.

Funkcje sterowane zdarzeniami utworzone za pomocą Cloud Run

Funkcje utworzone w konsoli Google Cloud lub za pomocą interfejsu Cloud RunAdmin API wymagają osobnego tworzenia i zarządzania wyzwalaczami zdarzeń. Gorąco zalecamy zapoznanie się z domyślnym działaniem każdego typu reguły:

Funkcje oparte na zdarzeniach utworzone za pomocą interfejsu Cloud Functions API w wersji 2

Funkcje utworzone za pomocą interfejsu Cloud Functions API w wersji 2, na przykład za pomocą interfejsu Cloud Functions gcloud CLI, interfejsu API typu REST lub Terraform, będą tworzyć i zarządzać w Twoim imieniu wyzwalaczami zdarzeń. 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 powtórzenia w przypadku funkcji wywoływanej przez zdarzenie, Cloud Functions będzie ona powtarzać nieudane wywołanie funkcji, dopóki nie zakończy się pomyślnie lub nie upłynie czas na powtórzenie.

Jeśli w przypadku funkcji nie są włączone ponowne próby (co jest domyślnym ustawieniem), funkcja zawsze raportuje, że została wykonana pomyślnie, a w jej dziennikach mogą się pojawić kody odpowiedzi 200 OK. Dzieje się tak nawet wtedy, gdy funkcja napotka błąd. Aby wyraźnie określić, kiedy funkcja napotka błąd, odpowiednio zgłaszaj błędy.

Włączanie i wyłączanie prób ponownych.

Konfigurowanie prób ponownego połączenia z poziomu kodu funkcji

Za pomocą funkcji Cloud Functions for Firebase możesz włączyć w kodzie funkcję prób ponownych. Aby to zrobić w przypadku funkcji tła, takiej jak functions.foo.onBar(myHandler);, użyj funkcji runWith i skonfiguruj zasady postępowania w przypadku błędu:

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

Ustawienie true w taki sposób powoduje, że funkcja będzie próbować ponownie w przypadku niepowodzenia.

Okno ponownego próby

W przypadku funkcji 2 generacji to okno próby ponownego wykonania kończy się po 24 godzinach. W przypadku funkcji 1 generacji wygasa ona po 7 dniach. Cloud Functions powtarza nowo utworzone funkcje wywoływane przez zdarzenia, stosując strategię wzrastającego czasu do ponowienia, w ramach 10–600 sekund. Ta zasada jest stosowana do nowych funkcji podczas ich pierwszego wdrożenia. Nie ma ona zastosowania do istniejących funkcji, które zostały wdrożone przed wprowadzeniem zmian opisanych w tych informacjach o wersji, nawet jeśli funkcje te zostaną ponownie wdrożone.

Sprawdzone metody

W tej sekcji znajdziesz sprawdzone metody korzystania z powtórnych prób.

Ponowne próby w przypadku błędów przejściowych

Funkcja jest nieustannie powtarzana, dopóki nie zostanie wykonana pomyślnie, dlatego przed włączeniem prób ponownego wykonania należy wyeliminować z kodu trwałe błędy, takie jak błędy w programie. Powtórzenia najlepiej sprawdzają się w przypadku sporadycznych lub przejściowych awarii, które mają dużą szansę na rozwiązanie po ponownym próbie, takich jak niestabilny punkt końcowy usługi lub limit czasu.

Ustaw warunek zakończenia, aby uniknąć nieskończonej pętli prób.

Dobrą praktyką jest ochrona funkcji przed ciągłym pętlą przy użyciu prób ponownego połączenia. Możesz to zrobić, dodając dobrze zdefiniowany warunek zakończenia przed rozpoczęciem przetwarzania funkcji. Pamiętaj, że ta metoda działa tylko wtedy, gdy funkcja uruchamia się prawidłowo i może ocenić warunek zakończenia.

Prostym, ale skutecznym podejściem jest odrzucanie zdarzeń z danymi czasowymi starszymi niż określony czas. Pomaga to uniknąć nadmiernego wykonywania, gdy błędy są trwałe lub trwają dłużej niż oczekiwano.

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żywanie catch w ramach obietnic

Jeśli w przypadku funkcji włączone jest ponawianie, każda nieprzetworzona obsługa błędu spowoduje ponowne wykonanie funkcji. Upewnij się, że Twój kod rejestruje wszystkie błędy, które nie powinny powodować ponownego próby.

Oto przykład tego, co należy zrobić:

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

uczynić funkcje reagujące na zdarzenia idempotentnymi,

Funkcje reagujące na zdarzenia, które można ponownie uruchomić, muszą być idempotentne. Oto kilka ogólnych wskazówek dotyczących tworzenia idempotentnych funkcji:

  • Wiele zewnętrznych interfejsów API (np. Stripe) umożliwia podanie klucza idempotentności jako parametru. Jeśli używasz takiego interfejsu API, jako klucza idempotentności należy użyć identyfikatora zdarzenia.
  • Idempotencyczność sprawdza się w przypadku dostarczania co najmniej raz, ponieważ umożliwia bezpieczne ponowne próby. Dlatego ogólną sprawdzoną metodą pisania niezawodnego kodu jest połączenie idempotencji z powtórzeniami.
  • Upewnij się, że kod jest idempotentny wewnętrznie. Na przykład:
    • Upewnij się, że mutacje mogą wystąpić więcej niż raz bez zmiany wyniku.
    • Zapytanie stanu bazy danych w ramach transakcji przed jego zmianą.
    • Upewnij się, że wszystkie efekty uboczne są idempotentne.
  • Zaimplementuj kontrolę transakcji poza funkcją, niezależnie od kodu. Możesz na przykład zapisać stan, w którym jest zapisany fakt, że dany identyfikator zdarzenia został już przetworzony.
  • Rozwiązywanie problemu z duplikatowymi wywołaniami funkcji poza pasmem. Możesz na przykład utworzyć osobny proces czyszczenia, który będzie usuwał zduplikowane wywołania funkcji.

Konfigurowanie zasad ponawiania

W zależności od potrzeb funkcji możesz skonfigurować bezpośrednio zasady ponownych prób. Dzięki temu możesz skonfigurować dowolną kombinację tych ustawień:

  • Skrócenie okna prób ponownego połączenia z 7 dni do zaledwie 10 minut.
  • Zmień minimalny i maksymalny czas przerwy w przypadku strategii ponownego próby z wykładniczym odstępem.
  • Zmień strategię powtarzania na „ponów natychmiast”.
  • Skonfiguruj temat niedostarczonych komunikatów.
  • Ustaw maksymalną i minimalną liczbę prób dostarczenia.

Aby skonfigurować zasadę ponawiania:

  1. napisać funkcję HTTP,
  2. Użyj interfejsu API Pub/Sub, aby utworzyć subskrypcję Pub/Sub, podając jako docelowe adres URL funkcji.

Więcej informacji o konfigurowaniu Pub/Sub znajdziesz w dokumentacji Pub/Sub na temat obsługi błędów.