Mettre à niveau les fonctions Node.js de 1re génération vers la 2e génération

Les applications utilisant actuellement les fonctions de 1re génération devraient envisager de migrer vers la 2e génération en suivant les instructions de ce guide. Les fonctions de 2e génération utilisent Cloud Run pour offrir de meilleures performances, une meilleure configuration, une meilleure surveillance, et bien plus encore.

Les exemples de cette page supposent que vous utilisez JavaScript avec les modules CommonJS ( require des importations de style), mais les mêmes principes s'appliquent à JavaScript avec ESM ( import … from d'importations de style) et TypeScript.

Le processus migratoire

Les fonctions de 1ère et 2ème génération peuvent coexister côte à côte dans le même fichier. Cela permet une migration facile, pièce par pièce, lorsque vous êtes prêt. Nous vous recommandons de migrer une fonction à la fois, en effectuant des tests et des vérifications avant de continuer.

Vérifier les versions de Firebase CLI et firebase-function s

Assurez-vous d'utiliser au moins Firebase CLI version 12.00 et firebase-functions version 4.3.0 . Toute version plus récente prendra en charge la 2e génération ainsi que la 1re génération.

Mettre à jour les importations

Les fonctions de 2e génération sont importées à partir du sous-paquet v2 dans le SDK firebase-functions . Ce chemin d'importation différent est tout ce dont la CLI Firebase a besoin pour déterminer si elle doit déployer votre code de fonction en tant que fonction de 1ère ou de 2ème génération.

Le sous-package v2 est modulaire et nous vous recommandons d'importer uniquement le module spécifique dont vous avez besoin.

Avant : 1ère génération

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

Après : 2e génération

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

Mettre à jour les définitions de déclencheurs

Étant donné que le SDK de 2e génération favorise les importations modulaires, mettez à jour les définitions de déclencheurs pour refléter les importations modifiées de l'étape précédente.

Les arguments transmis aux rappels pour certains déclencheurs ont changé. Dans cet exemple, notez que les arguments du rappel onDocumentCreated ont été regroupés en un seul objet event . De plus, certains déclencheurs disposent de nouvelles fonctionnalités de configuration pratiques, comme l'option cors du déclencheur onRequest .

Avant : 1ère génération

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

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

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

Après : 2e génération

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

Utiliser la configuration paramétrée

Les fonctions de 2e génération abandonnent la prise en charge functions.config au profit d'une interface plus sécurisée pour définir les paramètres de configuration de manière déclarative dans votre base de code. Avec le nouveau module params , la CLI bloque le déploiement à moins que tous les paramètres n'aient une valeur valide, garantissant ainsi qu'une fonction n'est pas déployée avec une configuration manquante.

Migrer vers le sous-paquet params

Si vous utilisez la configuration d'environnement avec functions.config , vous pouvez migrer votre configuration existante vers une configuration paramétrée .

Avant : 1ère génération

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

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

  // ...
});

Après : 2e génération

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

  // ...
});

Définir les valeurs des paramètres

Lors du premier déploiement, la CLI Firebase vous demande toutes les valeurs des paramètres et enregistre les valeurs dans un fichier dotenv. Pour exporter vos valeurs Functions.config, exécutez firebase functions:config:export .

Pour plus de sécurité, vous pouvez également spécifier des types de paramètres et des règles de validation .

Cas particulier : clés API

Le module params s'intègre à Cloud Secret Manager, qui fournit un contrôle d'accès précis aux valeurs sensibles telles que les clés API. Voir les paramètres secrets pour plus d'informations.

Avant : 1ère génération

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

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

Après : 2e génération

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

Définir les options d'exécution

La configuration des options d'exécution a changé entre la 1ère et la 2ème génération. La 2e génération ajoute également une nouvelle capacité permettant de définir des options pour toutes les fonctions.

Avant : 1ère génération

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

Après : 2e génération

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

Utiliser la simultanéité

Un avantage significatif des fonctions de 2e génération est la capacité d'une seule instance de fonction à répondre à plusieurs requêtes à la fois. Cela peut réduire considérablement le nombre de démarrages à froid rencontrés par les utilisateurs finaux. Par défaut, la simultanéité est définie sur 80, mais vous pouvez la définir sur n'importe quelle valeur comprise entre 1 et 1 000 :

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

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

Le réglage de la simultanéité peut améliorer les performances et réduire le coût des fonctions. Apprenez-en davantage sur la simultanéité dans Autoriser les demandes simultanées .

Auditer l'utilisation des variables globales

Les fonctions de 1ère génération écrites sans concurrence peuvent utiliser des variables globales définies et lues à chaque requête. Lorsque la concurrence est activée et qu'une seule instance commence à traiter plusieurs requêtes à la fois, cela peut introduire des bogues dans votre fonction car les requêtes simultanées commencent à définir et à lire simultanément les variables globales.

Lors de la mise à niveau, vous pouvez définir le processeur de votre fonction sur gcf_gen1 et définir concurrency sur 1 pour restaurer le comportement de 1ère génération :

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

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

Cependant, cela n’est pas recommandé comme solution à long terme, car cela perd les avantages en termes de performances des fonctions de 2e génération. Au lieu de cela, auditez l'utilisation des variables globales dans vos fonctions et supprimez ces paramètres temporaires lorsque vous êtes prêt.

Migrer le trafic vers les nouvelles fonctions de 2e génération

Tout comme lors de la modification de la région ou du type de déclencheur d'une fonction , vous devrez donner un nouveau nom à la fonction de 2e génération et y migrer lentement le trafic.

Il n'est pas possible de mettre à niveau une fonction de la 1ère à la 2ème génération avec le même nom et d'exécuter firebase deploy . Cela entraînerait l'erreur :

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

Avant de suivre ces étapes, assurez-vous d'abord que votre fonction est idempotente , car la nouvelle version et l'ancienne version de votre fonction s'exécuteront en même temps pendant le changement. Par exemple, si vous disposez d'une fonction de 1re génération qui répond aux événements d'écriture dans Firestore, assurez-vous que répondre à une écriture deux fois, une fois par la fonction de 1re génération et une fois par la fonction de 2e génération, en réponse à ces événements, laisse votre application dans un état différent. état cohérent.

  1. Renommez la fonction dans votre code de fonctions. Par exemple, renommez resizeImage en resizeImageSecondGen .
  2. Déployez la fonction, de sorte que la fonction d'origine de 1ère génération et la fonction de 2e génération soient exécutées.
    1. Dans le cas de déclencheurs appelables, de file d'attente de tâches et HTTP, commencez à pointer tous les clients vers la fonction de 2e génération en mettant à jour le code client avec le nom ou l'URL de la fonction de 2e génération.
    2. Avec les déclencheurs en arrière-plan, les fonctions de 1re et 2e génération répondront à chaque événement immédiatement après le déploiement.
  3. Lorsque tout le trafic est migré, supprimez la fonction de 1ère génération à l'aide de la commande firebase functions:delete de la CLI Firebase.
    1. Vous pouvez éventuellement renommer la fonction de 2e génération pour qu'elle corresponde au nom de la fonction de 1re génération.