Aplikacje, które obecnie używają funkcji 1 generacji, powinny rozważyć migrację do 2 generacji zgodnie z instrukcjami w tym przewodniku. Funkcje 2 generacji korzystają z Cloud Run, aby między innymi zwiększyć wydajność, konfigurację i lepsze monitorowanie.
W przykładach na tej stronie zakładamy, że używasz JavaScriptu z modułami CommonJS (importy stylów require
), ale te same zasady dotyczą JavaScriptu z importami stylów ESM (import … from
) i TypeScriptu.
Proces migracji
Funkcje 1 generacji i 2 generacji mogą występować obok siebie w tym samym pliku. Pozwala to na łatwą migrację etapami, gdy wszystko będzie gotowe. Zalecamy, aby przed przejściem dalej przenosić po jednej funkcji, a potem ją testować i weryfikować.
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 obsługuje zarówno urządzenia 2 i 1 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 czy 2 generacji.
Podpakiet v2
jest modułowy, dlatego zalecamy zaimportowanie tylko konkretnego modułu.
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
Pakiet SDK 2 generacji preferuje importowanie modułowe, dlatego zaktualizuj definicje aktywatorów, aby odzwierciedlały zmiany w importach z poprzedniego kroku.
Argumenty przekazywane do wywołań zwrotnych w przypadku niektórych aktywatorów uległy zmianie. Zwróć uwagę, że w tym przykładzie argumenty wywołania zwrotnego onDocumentCreated
zostały skonsolidowane w jednym obiekcie event
. Poza tym niektóre aktywatory mają nowe, wygodne funkcje konfiguracji, takie jak opcja 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 używałeś konfiguracji środowiska z functions.config
, możesz przenieść istniejącą konfigurację do konfiguracji 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 parametrów i zapisuje wartości w pliku dotenv. Aby wyeksportować wartościfunctions.config, uruchom polecenie 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. Więcej informacji znajdziesz w sekcji Parametry obiektu tajnego.
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
Konfiguracja opcji środowiska wykonawczego zmieniła się między 1 a 2 generacją. W 2 generacji dostępna jest też nowa możliwość ustawiania opcji 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ść obsługi przez jedną jej instancję więcej niż 1 żądania jednocześnie. Może to znacznie zmniejszyć liczbę uruchomień „na zimno” u użytkowników. Domyślnie równoczesność jest ustawiona na 80, ale można ustawić dowolną wartość z zakresu 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 tworzone bez uwzględniania równoczesności mogą używać zmiennych globalnych, które są ustawiane i odczytywane w przypadku każdego żądania. Gdy równoczesność jest włączona i pojedyncza instancja zaczyna obsługiwać wiele żądań jednocześnie, może to wprowadzić w Twojej funkcji błędy, gdy równoczesne żądania zaczynają ustawiać i odczytywać zmienne globalne jednocześnie.
Podczas uaktualniania możesz ustawić procesor funkcji na gcf_gen1
, a concurrency
na 1, aby przywrócić działanie 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ę korzyści w zakresie wydajności funkcji 2 generacji. Zamiast tego sprawdź użycie zmiennych globalnych w funkcjach i w razie potrzeby usuń te ustawienia tymczasowe.
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.
- Zmień nazwę funkcji w kodzie funkcji. Możesz na przykład zmienić nazwę
resizeImage
naresizeImageSecondGen
. - Wdróż funkcję, aby działała zarówno pierwotna funkcja 1 generacji, jak i 2 generacji.
- 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.
- Dzięki aktywatorom w tle funkcje 1 generacji i 2 generacji będą reagować na każde zdarzenie natychmiast po wdrożeniu.
- Gdy cały ruch zostanie wyłączony, usuń funkcję 1 generacji za pomocą polecenia
firebase functions:delete
w interfejsie wiersza poleceń Firebase.- Opcjonalnie zmień nazwę funkcji 2 generacji, aby pasowała do nazwy funkcji 1 generacji.