Aplikacje korzystające z funkcji 1 generacji powinny rozważyć przejście na funkcje 2 generacji zgodnie z instrukcjami w tym przewodniku. Funkcje 2 generacji korzystają z Cloud Run, aby zapewnić większą wydajność, lepszą konfigurację, lepsze monitorowanie i inne korzyści.
Przykłady na tej stronie zakładają, że używasz JavaScriptu z modułami CommonJS (requireimporty stylów), ale te same zasady mają zastosowanie do JavaScriptu z modułami ESM (import … fromimporty stylów) i TypeScriptu.
Proces migracji
Funkcje 1 generacji i 2 generacji mogą współistnieć w tym samym pliku. Umożliwia to łatwą migrację krok po kroku, gdy tylko będziesz gotowy. Zalecamy migrację po jednej funkcji naraz, a przed kontynuowaniem przeprowadzanie testów i weryfikacji.
Sprawdź wersje wiersza poleceń Firebase i firebase-function
Upewnij się, że używasz co najmniej wersji 12.00 wiersza poleceń Firebase i wersji firebase-functions4.3.0. Każda nowsza wersja będzie obsługiwać zarówno 2, jak i 1 generację.
Aktualizowanie importów
Funkcje 2 generacji są importowane z podpakietu v2 w pakiecie SDK firebase-functions.
Ta inna ścieżka importu jest wszystkim, czego potrzebuje interfejs CLI Firebase, aby określić, czy wdrożyć kod funkcji jako funkcję 1 czy 2 generacji.
Pakiet podrzędny v2 jest modułowy, dlatego zalecamy importowanie tylko konkretnego modułu, którego potrzebujesz.
Wcześniej: 1 generacja
const functions = require("firebase-functions/v1");
Po: 2 generacja
// explicitly import each trigger
const {onRequest} = require("firebase-functions/v2/https");
const {onDocumentCreated} = require("firebase-functions/v2/firestore");
Aktualizowanie definicji aktywatorów
Pakiet SDK drugiej generacji preferuje importy modułowe, więc zaktualizuj definicje reguł, aby odzwierciedlały zmiany importów z poprzedniego kroku.
Argumenty przekazywane do wywołań zwrotnych w przypadku niektórych typów wyzwalaczy uległy zmianie. W tym przykładzie zwróć uwagę, że argumenty wywołania zwrotnego onDocumentCreated zostały skonsolidowane w jeden obiekt event. Niektóre wyzwalacze mają też nowe, wygodne funkcje konfiguracji, np. wyzwalacz onRequest ma opcję cors.
Wcześniej: 1 generacja
const functions = require("firebase-functions/v1");
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żywanie konfiguracji sparametryzowanej
Funkcje 2 generacji nie obsługują już functions.config. Zamiast tego używają bezpieczniejszego interfejsu do deklaratywnego definiowania parametrów konfiguracji w kodzie.
Dzięki nowemu modułowi params interfejs CLI blokuje wdrażanie, dopóki wszystkie parametry nie będą miały prawidłowej wartości. Dzięki temu funkcja nie zostanie wdrożona bez brakującej konfiguracji.
Wcześniej: 1 generacja
const functions = require("firebase-functions/v1");
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());
// ...
}
);
Jeśli masz istniejącą konfigurację środowiska z functions.config, przenieś ją w ramach uaktualnienia do 2 generacji.
Interfejs API functions.config został wycofany i zostanie wyłączony w marcu 2027 r.
Po tym terminie wdrożenia z wartością functions.config nie będą się powodzić.
Aby zapobiec niepowodzeniom wdrażania, przenieś konfigurację do usługi Cloud Secret Manager za pomocą interfejsu wiersza poleceń Firebase. Jest to zdecydowanie zalecane jako najskuteczniejszy i najbezpieczniejszy sposób przenoszenia konfiguracji.
Eksportowanie konfiguracji za pomocą interfejsu wiersza poleceń Firebase
Użyj polecenia
config export, aby wyeksportować istniejącą konfigurację środowiska do nowego obiektu tajnego w usłudze Cloud Secret Manager:$ firebase functions:config:export i This command retrieves your Runtime Config values (accessed via functions.config()) and exports them as a Secret Manager secret. i Fetching your existing functions.config() from your project... ✔ Fetched your existing functions.config(). i Configuration to be exported: ⚠ This may contain sensitive data. Do not share this output. { ... } ✔ What would you like to name the new secret for your configuration? RUNTIME_CONFIG ✔ Created new secret version projects/project/secrets/RUNTIME_CONFIG/versions/1```Aktualizowanie kodu funkcji w celu powiązania obiektów tajnych
Aby użyć konfiguracji przechowywanej w nowym obiekcie tajnym w usłudze Cloud Secret Manager, użyj w źródle funkcji interfejsu
defineJsonSecretAPI. Upewnij się też, że klucze są powiązane ze wszystkimi funkcjami, które ich potrzebują.Przed
const functions = require("firebase-functions/v1"); exports.myFunction = functions.https.onRequest((req, res) => { const apiKey = functions.config().someapi.key; // ... });Po
const { onRequest } = require("firebase-functions/v2/https"); const { defineJsonSecret } = require("firebase-functions/params"); const config = defineJsonSecret("RUNTIME_CONFIG"); exports.myFunction = onRequest( // Bind secret to your function { secrets: [config] }, (req, res) => { // Access secret values via .value() const apiKey = config.value().someapi.key; // ... });Wdrażanie funkcji
Wdróż zaktualizowane funkcje, aby zastosować zmiany i powiązać uprawnienia do wpisu tajnego.
firebase deploy --only functions:<your-function-name>
Ustawianie opcji środowiska wykonawczego
Konfiguracja opcji środowiska wykonawczego zmieniła się między 1 a 2 generacją. 2 generacja ma też nową funkcję ustawiania opcji dla wszystkich funkcji.
Wcześniej: 1 generacja
const functions = require("firebase-functions/v1");
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) => {
/* ... */
});
Aktualizowanie domyślnego konta usługi (opcjonalnie)
Funkcje 1 generacji używają domyślnego konta usługi Google App Engine do autoryzowania dostępu do interfejsów API Firebase, a funkcje 2 generacji używają domyślnego konta usługi Compute Engine. Ta różnica może powodować problemy z uprawnieniami w przypadku funkcji przeniesionych do drugiej generacji, jeśli konto usługi pierwszej generacji ma specjalne uprawnienia. Jeśli nie zmieniono żadnych uprawnień konta usługi, możesz pominąć ten krok.
Zalecane rozwiązanie to jawne przypisanie istniejącego domyślnego konta usługi App Engine 1 generacji do funkcji, które chcesz przenieść do 2 generacji, zastępując domyślne konto 2 generacji. Możesz to zrobić, upewniając się, że każda migrowana funkcja ustawia prawidłową wartość zmiennej serviceAccountEmail:
const {onRequest} = require("firebase-functions/https");
const {onDocumentCreated} = require("firebase-functions/v2/firestore");
const {setGlobalOptions} = require("firebase-functions");
// Use the App Engine default service account for all functions
setGlobalOptions({serviceAccountEmail: '<my-project-number>@<wbr>appspot.gserviceaccount.com'});
// Now I use the App Engine default service account.
exports.date = onRequest({cors: true}, (req, res) => {
// ...
});
// I do too!
exports.uppercase = onDocumentCreated("my-collection/{docId}", (event) => {
// ...
});
Możesz też zmodyfikować szczegóły konta usługi, aby dopasować wszystkie niezbędne uprawnienia zarówno na domyślnym koncie usługi App Engine (w przypadku platformy 1 generacji), jak i na domyślnym koncie usługi Compute Engine (w przypadku platformy 2 generacji).
Korzystanie z równoczesności
Istotną zaletą funkcji 2 generacji jest możliwość obsługiwania przez jedną instancję funkcji więcej niż 1 żądania naraz. Może to znacznie zmniejszyć liczbę uruchomień „na zimno” u użytkowników. Domyślnie równoczesność jest ustawiona na 80, ale możesz 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 współbieżności może poprawić wydajność i obniżyć koszty funkcji. Więcej informacji o równoczesności znajdziesz w sekcji Zezwalaj na równoczesne żądania.
Sprawdzanie użycia zmiennych globalnych
Funkcje 1 generacji napisane bez uwzględnienia współbieżności mogą używać zmiennych globalnych, które są ustawiane i odczytywane w przypadku każdego żądania. Jeśli współbieżność jest włączona, a pojedyncza instancja zaczyna obsługiwać wiele żądań jednocześnie, w funkcji mogą pojawić się błędy, ponieważ współbieżne żądania zaczynają jednocześnie ustawiać i odczytywać zmienne globalne.
Podczas uaktualniania możesz ustawić wartość CPU funkcji na gcf_gen1 i wartość concurrency na 1, aby przywrócić działanie funkcji 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 jako rozwiązanie długoterminowe, ponieważ powoduje utratę korzyści związanych z wydajnością funkcji 2 generacji. Zamiast tego sprawdź użycie zmiennych globalnych w funkcjach i usuń te ustawienia tymczasowe, gdy będziesz gotowy(-a).
Przenoszenie ruchu do nowych funkcji 2 generacji
Podobnie jak w przypadku zmiany regionu lub typu wyzwalacza funkcji, musisz nadać funkcji 2 generacji nową nazwę i stopniowo przenosić do niej ruch.
Nie można uaktualnić funkcji z 1. generacji do 2. generacji o tej samej nazwie i uruchomić firebase deploy. Spowoduje to błąd:
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 funkcja jest idempotentna, ponieważ podczas zmiany będą działać jednocześnie nowa i stara wersja funkcji. Jeśli na przykład masz funkcję 1 generacji, która reaguje na zdarzenia zapisu w Firestore, upewnij się, że reagowanie na zapis dwukrotnie – raz przez funkcję 1 generacji i raz przez funkcję 2 generacji – w odpowiedzi na te zdarzenia pozostawia aplikację w spójnym stanie.
- Zmień nazwę funkcji w jej kodzie. Na przykład zmień nazwę
resizeImagenaresizeImageSecondGen. - Wdróż funkcję, aby działały zarówno oryginalna funkcja 1 generacji, jak i funkcja 2 generacji.
- W przypadku aktywatorów wywoływanych, kolejki zadań i HTTP zacznij kierować wszystkich klientów do funkcji 2 generacji, aktualizując kod klienta o nazwę lub adres URL funkcji 2 generacji.
- W przypadku reguł w tle zarówno funkcje 1 generacji, jak i 2 generacji będą reagować na każde zdarzenie natychmiast po wdrożeniu.
- Gdy cały ruch zostanie przeniesiony, usuń funkcję 1 generacji za pomocą polecenia
firebase functions:deletewiersza poleceń Firebase.- Opcjonalnie zmień nazwę funkcji 2 generacji, aby pasowała do nazwy funkcji 1 generacji.