Uaktualnij funkcje Node.js 1 generacji do 2 generacji

Aplikacje, które obecnie używają funkcji 1 generacji, powinny rozważyć migrację do 2 generacji postępując zgodnie z instrukcjami w tym przewodniku. Funkcje 2 generacji używają Cloud Run do zapewniania lepszą wydajność, lepsza konfiguracja, lepsze monitorowanie i inne korzyści.

W przykładach na tej stronie zakładamy, że używasz JavaScriptu z modułami CommonJS. (require importów stylów), ale w przypadku JavaScriptu w ESM obowiązują te same zasady (import … from importów stylów) i TypeScript.

Proces migracji

Funkcje 1 generacji i 2 generacji mogą występować obok siebie w tym samym pliku. Ten który pozwala na łatwą migrację – krok po kroku. Zalecamy Przeprowadzanie migracji po jednej funkcji oraz przeprowadzanie testów i weryfikacji dalej.

Weryfikacja interfejsu wiersza poleceń Firebase i wersji firebase-function

Upewnij się, że używasz interfejsu wiersza poleceń Firebase co najmniej w wersji 12.00 i firebase-functions w wersji 4.3.0. Każda nowsza wersja będzie obsługiwać 2 generację jako oraz pierwszej generacji.

Aktualizowanie importów

Importuj funkcje 2 generacji z podpakietu v2 w pakiecie SDK firebase-functions. Ta inna ścieżka importu to wszystko, czego interfejs wiersza poleceń Firebase potrzebuje do określenia, czy wdrożyć kod funkcji jako funkcję 1 lub 2 generacji.

Podpakiet v2 jest modułowy. Zalecamy importowanie tylko określonych który będzie Ci potrzebny.

Przed: 1 generacja

const functions = require("firebase-functions");

Po: 2 generacja

// explicitly import each trigger
const {onRequest} = require("firebase-functions/v2/https");
const {onDocumentCreated} = require("firebase-functions/v2/firestore");

Zaktualizuj definicje aktywatorów

Ponieważ pakiet SDK 2 generacji preferuje importowanie modułowe, zaktualizuj definicje aktywatorów na odzwierciedlają zmiany importów z poprzedniego kroku.

Argumenty przekazywane do wywołań zwrotnych w przypadku niektórych aktywatorów uległy zmianie. W tym zwróć uwagę, że argumenty wywołania zwrotnego onDocumentCreated zostały skonsolidowane w jeden obiekt event. Dodatkowo niektóre aktywatory mają nowe wygodne funkcje konfiguracji, takie jak cors aktywatora onRequest .

Przed: 1 generacja

const functions = require("firebase-functions");

exports.date = functions.https.onRequest((req, res) => {
  // ...
});

exports.uppercase = functions.firestore
  .document("my-collection/{docId}")
  .onCreate((change, context) => {
    // ...
  });

Po: 2 generacja

const {onRequest} = require("firebase-functions/v2/https");
const {onDocumentCreated} = require("firebase-functions/v2/firestore");

exports.date = onRequest({cors: true}, (req, res) => {
  // ...
});

exports.uppercase = onDocumentCreated("my-collection/{docId}", (event) => {
  /* ... */
});

Użyj konfiguracji z parametrami

Funkcje 2 generacji przestają obsługiwać interfejs functions.config na rzecz bezpieczniejszego interfejsu do deklaratywnego definiowania parametrów konfiguracyjnych w bazie kodu. W nowym module params interfejs wiersza poleceń blokuje wdrożenie, chyba że wszystkie parametry mają prawidłową wartość. Dzięki temu funkcja nie zostanie wdrożona z brakującą konfiguracją.

Przenieś do podpakietu params

Jeśli konfiguracja środowiska była przez Ciebie używana z functions.config, może przenieść istniejącą konfigurację do konfigurację z parametrami.

Przed: 1 generacja

const functions = require("firebase-functions");

exports.date = functions.https.onRequest((req, res) => {
  const date = new Date();
  const formattedDate =
date.toLocaleDateString(functions.config().dateformat);

  // ...
});

Po: 2 generacja

const {onRequest} = require("firebase-functions/v2/https");
const {defineString} = require("firebase-functions/params");

const dateFormat = defineString("DATE_FORMAT");

exports.date = onRequest((req, res) => {
  const date = new Date();
  const formattedDate = date.toLocaleDateString(dateFormat.value());

  // ...
});

Ustawianie wartości parametrów

Przy pierwszym wdrożeniu interfejs wiersza poleceń Firebase prosi o podanie wszystkich wartości i zapisać je w pliku dotenv. Aby wyeksportować features.config, uruchom firebase functions:config:export.

Aby zwiększyć bezpieczeństwo, możesz też określić typy parametrów i reguły weryfikacji.

Przypadek specjalny: klucze interfejsu API

Moduł params integruje się z usługą Cloud Secret Manager, która zapewnia szczegółową kontrolę dostępu do wartości poufnych, takich jak klucze interfejsu API. Zobacz parametry tajne .

Przed: 1 generacja

const functions = require("firebase-functions");

exports.getQuote = functions.https.onRequest(async (req, res) => {
  const quote = await fetchMotivationalQuote(functions.config().apiKey);
  // ...
});

Po: 2 generacja

const {onRequest} = require("firebase-functions/v2/https");
const {defineSecret} = require("firebase-functions/params");

// Define the secret parameter
const apiKey = defineSecret("API_KEY");

exports.getQuote = onRequest(
  // make the secret available to this function
  { secrets: [apiKey] },
  async (req, res) => {
    // retrieve the value of the secret
    const quote = await fetchMotivationalQuote(apiKey.value());
    // ...
  }
);

Ustaw opcje środowiska wykonawczego

konfigurację opcji środowiska wykonawczego. zostało zmienione między 1 a 2 generacją. 2 generacji udostępnia też nową możliwość ustawić opcje dla wszystkich funkcji.

Przed: 1 generacja

const functions = require("firebase-functions");

exports.date = functions
  .runWith({
    // Keep 5 instances warm for this latency-critical function
    minInstances: 5,
  })
  // locate function closest to users
  .region("asia-northeast1")
  .https.onRequest((req, res) => {
    // ...
  });

exports.uppercase = functions
  // locate function closest to users and database
  .region("asia-northeast1")
  .firestore.document("my-collection/{docId}")
  .onCreate((change, context) => {
    // ...
  });

Po: 2 generacja

const {onRequest} = require("firebase-functions/v2/https");
const {onDocumentCreated} = require("firebase-functions/v2/firestore");
const {setGlobalOptions} = require("firebase-functions/v2");

// locate all functions closest to users
setGlobalOptions({ region: "asia-northeast1" });

exports.date = onRequest({
    // Keep 5 instances warm for this latency-critical function
    minInstances: 5,
  }, (req, res) => {
  // ...
});

exports.uppercase = onDocumentCreated("my-collection/{docId}", (event) => {
  /* ... */
});

Używaj równoczesności

Ważną zaletą funkcji 2 generacji jest możliwość do obsługi wielu żądań jednocześnie. Może to znacznie zmniejszyć liczbę uruchomień „na zimno” zaobserwowanych u użytkowników. Domyślnie równoczesność to jest ustawiony na 80, ale możesz ustawić dowolną wartość od 1 do 1000:

const {onRequest} = require("firebase-functions/v2/https");

exports.date = onRequest({
    // set concurrency value
    concurrency: 500
  },
  (req, res) => {
    // ...
});

Dostrajanie równoczesności może zwiększyć wydajność i zmniejszyć koszty funkcji. Więcej informacji o równoczesności znajdziesz w artykule Zezwalanie na żądania równoczesne.

Kontrola wykorzystania zmiennych globalnych

Funkcje 1 generacji utworzone bez uwzględniania równoczesności mogą korzystać ze zmiennych globalnych które są skonfigurowane i odczytywane w przypadku każdego żądania. Gdy włączona jest równoczesność, a jeden instancji zaczyna obsługiwać wiele żądań jednocześnie, może to wprowadzić błędy zaczyna się ustawiać i odczytywać zmienne globalne, a także funkcję w żądaniach równoczesnych. jednocześnie.

Podczas uaktualniania możesz ustawić procesor funkcji funkcji na gcf_gen1 i ustawić concurrency na 1, aby przywrócić zachowanie 1 generacji:

const {onRequest} = require("firebase-functions/v2/https");

exports.date = onRequest({
    // TEMPORARY FIX: remove concurrency
    cpu: "gcf_gen1",
    concurrency: 1
  },
  (req, res) => {
    // ...
});

Nie jest to jednak zalecane rozwiązanie długoterminowe, ponieważ powoduje utratę i zwiększa wydajność funkcji 2 generacji. Zamiast tego kontroluj użycie zmiennych w funkcjach i usuń te ustawienia tymczasowe gotowe.

Przeprowadź migrację ruchu do nowych funkcji 2 generacji

Tak jak przy zmianie regionu lub typu aktywatora funkcji, musisz nadać funkcji 2 generacji nową nazwę i stopniowo przenosić do niej ruch.

Nie można uaktualnić funkcji z 1 do 2 generacji o tej samej nazwie i uruchomić firebase deploy. Spowoduje to wystąpienie błędu:

Upgrading from GCFv1 to GCFv2 is not yet supported. Please delete your old function or wait for this feature to be ready.

Zanim wykonasz te czynności, upewnij się, że Twoja funkcja jest idempotentna, ponieważ podczas zmiany zarówno nowa, jak i stara wersja będą uruchamiane w tym samym czasie. Jeśli na przykład masz funkcję 1 generacji, która odpowiada na zapis zdarzeń w Firestore, upewnij się, że odpowiadając na zapis 2 razy: raz przez funkcję 1 generacji i raz przez funkcję 2 generacji, w odpowiedzi na te zdarzenia pozostawiasz aplikację w spójnym stanie.

  1. Zmień nazwę funkcji w kodzie funkcji. Możesz na przykład zmienić nazwę resizeImage na resizeImageSecondGen.
  2. Wdróż funkcję, aby działała zarówno pierwotna funkcja 1 generacji, jak i 2 generacji.
    1. W przypadku aktywatorów wywoływanych, kolejki zadań i aktywatorów HTTP zacznij wskazywać wszystkim klientom funkcję 2 generacji, aktualizując kod klienta o nazwę lub adres URL funkcji 2 generacji.
    2. Dzięki aktywatorom w tle funkcje 1 generacji i 2 generacji będą reagować na każde zdarzenie natychmiast po wdrożeniu.
  3. Gdy cały ruch zostanie wyłączony, usuń funkcję 1 generacji za pomocą polecenia firebase functions:delete w interfejsie wiersza poleceń Firebase.
    1. Opcjonalnie zmień nazwę funkcji 2 generacji, aby pasowała do nazwy funkcji 1 generacji.