Node.js-Funktionen der 1. Generation auf die 2. Generation umstellen

Apps, die Funktionen der 1. Generation verwenden, sollten gemäß der Anleitung in diesem Leitfaden zur 2. Generation migriert werden. Funktionen der 2. Generation verwenden Cloud Run, um eine bessere Leistung, bessere Konfiguration, besseres Monitoring und mehr zu bieten.

In den Beispielen auf dieser Seite wird davon ausgegangen, dass Sie JavaScript mit CommonJS-Modulen (require-Importe) verwenden. Die gleichen Prinzipien gelten jedoch auch für JavaScript mit ESM (import … from-Importe) und TypeScript.

Der Migrationsvorgang

Funktionen der 1. und 2. Generation können in derselben Datei nebeneinander vorhanden sein. So können Sie die Migration ganz einfach nach und nach durchführen, wenn Sie bereit sind. Wir empfehlen, jeweils nur eine Funktion zu migrieren und vor dem Fortfahren Tests und Überprüfungen durchzuführen.

Versionen von Firebase CLI und firebase-function prüfen

Achten Sie darauf, dass Sie mindestens die Firebase CLI-Version 12.00 und die firebase-functions-Version 4.3.0 verwenden. Neuere Versionen unterstützen sowohl die 2. als auch die 1. Generation.

Importe aktualisieren

Funktionen der 2. Generation werden aus dem Unterpaket v2 im firebase-functions-SDK importiert. Dieser andere Importpfad ist alles, was die Firebase-CLI benötigt, um zu bestimmen, ob Ihr Funktionscode als Funktion der 1. oder 2. Generation bereitgestellt werden soll.

Das Unterpaket v2 ist modular aufgebaut. Wir empfehlen, nur das benötigte Modul zu importieren.

Vorher: 1. Generation

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

Nachher: 2. Generation

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

Triggerdefinitionen aktualisieren

Da im SDK der 2. Generation modulare Importe bevorzugt werden, müssen Sie die Triggerdefinitionen entsprechend den geänderten Importen aus dem vorherigen Schritt aktualisieren.

Die Argumente, die an Callbacks für einige Trigger übergeben werden, haben sich geändert. In diesem Beispiel wurden die Argumente für den onDocumentCreated-Callback in einem einzelnen event-Objekt zusammengefasst. Außerdem haben einige Trigger praktische neue Konfigurationsfunktionen, z. B. die Option cors des Triggers onRequest.

Vorher: 1. Generation

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

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

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

Nachher: 2. Generation

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) => {
  /* ... */
});

Parametrisierte Konfiguration verwenden

Bei Funktionen der 2. Generation wird die Unterstützung für functions.config zugunsten einer sichereren Schnittstelle zum deklarativen Definieren von Konfigurationsparametern in Ihrem Code eingestellt. Mit dem neuen params-Modul blockiert die CLI die Bereitstellung, sofern nicht alle Parameter einen gültigen Wert haben. So wird verhindert, dass eine Funktion ohne Konfiguration bereitgestellt wird.

Zum Unterpaket params migrieren

Wenn Sie die Umgebungskonfiguration mit functions.config verwendet haben, können Sie Ihre vorhandene Konfiguration zu einer parametrisierten Konfiguration migrieren.

Vorher: 1. Generation

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

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

  // ...
});

Nachher: 2. Generation

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());

  // ...
});

Parameterwerte festlegen

Beim ersten Bereitstellen werden Sie von der Firebase CLI aufgefordert, alle Parameterwerte anzugeben. Die Werte werden in einer dotenv-Datei gespeichert. Führen Sie firebase functions:config:export aus, um die Werte von „functions.config“ zu exportieren.

Für zusätzliche Sicherheit können Sie auch Parametertypen und Validierungsregeln angeben.

Sonderfall: API-Schlüssel

Das Modul params lässt sich in Cloud Secret Manager einbinden, das eine detaillierte Zugriffssteuerung für vertrauliche Werte wie API-Schlüssel bietet. Weitere Informationen finden Sie unter Geheime Parameter.

Vorher: 1. Generation

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

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

Nachher: 2. Generation

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());
    // ...
  }
);

Laufzeitoptionen festlegen

Die Konfiguration von Laufzeitoptionen hat sich zwischen der 1. und der 2. Generation geändert. In der 2. Generation wurde außerdem eine neue Funktion zum Festlegen von Optionen für alle Funktionen hinzugefügt.

Vorher: 1. Generation

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) => {
    // ...
  });

Nachher: 2. Generation

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) => {
  /* ... */
});

Gleichzeitigkeit verwenden

Ein wesentlicher Vorteil von Funktionen der 2. Generation ist die Möglichkeit, dass eine einzelne Funktionsinstanz mehrere Anfragen gleichzeitig verarbeiten kann. So kann die Anzahl der Kaltstarts für Endnutzer erheblich reduziert werden. Standardmäßig ist die Nebenläufigkeit auf 80 festgelegt. Sie können sie jedoch auf einen beliebigen Wert zwischen 1 und 1.000 festlegen:

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

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

Durch das Optimieren der Parallelität kann die Leistung verbessert und die Kosten für Funktionen gesenkt werden. Weitere Informationen zur Gleichzeitigkeit

Verwendung globaler Variablen prüfen

Funktionen der 1. Generation, die nicht für die gleichzeitige Ausführung konzipiert wurden, verwenden möglicherweise globale Variablen, die bei jeder Anfrage festgelegt und gelesen werden. Wenn die Nebenläufigkeit aktiviert ist und eine einzelne Instanz beginnt, mehrere Anfragen gleichzeitig zu verarbeiten, kann dies zu Fehlern in Ihrer Funktion führen, da gleichzeitige Anfragen globale Variablen gleichzeitig festlegen und lesen.

Während des Upgrades können Sie die CPU Ihrer Funktion auf gcf_gen1 und concurrency auf 1 festlegen, um das Verhalten der 1. Generation wiederherzustellen:

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

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

Dies wird jedoch nicht als langfristige Lösung empfohlen, da die Leistungsvorteile von Funktionen der 2. Generation verloren gehen. Prüfen Sie stattdessen die Verwendung globaler Variablen in Ihren Funktionen und entfernen Sie diese temporären Einstellungen, wenn Sie bereit sind.

Traffic zu den neuen 2nd gen-Funktionen migrieren

Genau wie beim Ändern der Region oder des Triggertyps einer Funktion müssen Sie der 2nd gen-Funktion einen neuen Namen geben und den Traffic langsam darauf umstellen.

Es ist nicht möglich, eine Funktion der 1. Generation mit demselben Namen auf die 2. Generation zu aktualisieren und firebase deploy auszuführen. Andernfalls wird folgender Fehler ausgegeben:

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

Bevor Sie diese Schritte ausführen, sollten Sie prüfen, ob Ihre Funktion idempotent ist, da während der Änderung sowohl die neue als auch die alte Version Ihrer Funktion gleichzeitig ausgeführt werden. Wenn Sie beispielsweise eine Funktion der 1. Generation haben, die auf Schreibereignisse in Firestore reagiert, muss Ihre App in einem konsistenten Zustand bleiben, wenn zweimal auf ein Schreibereignis reagiert wird, einmal von der Funktion der 1. Generation und einmal von der Funktion der 2. Generation.

  1. Benennen Sie die Funktion im Code Ihrer Funktionen um. Benennen Sie beispielsweise resizeImage in resizeImageSecondGen um.
  2. Stellen Sie die Funktion bereit, sodass sowohl die ursprüngliche Funktion der 1. Generation als auch die Funktion der 2. Generation ausgeführt werden.
    1. Bei aufrufbaren, Task Queue- und HTTP-Triggern müssen Sie alle Clients auf die Funktion der 2. Generation verweisen, indem Sie den Clientcode mit dem Namen oder der URL der Funktion der 2. Generation aktualisieren.
    2. Bei Hintergrundtriggern reagieren sowohl die Funktionen der 1. als auch der 2. Generation nach der Bereitstellung sofort auf jedes Ereignis.
  3. Wenn der gesamte Traffic migriert wurde, löschen Sie die Funktion der 1. Generation mit dem Befehl firebase functions:delete der Firebase CLI.
    1. Benennen Sie die Funktion der 2. Generation optional so um, dass sie dem Namen der Funktion der 1. Generation entspricht.