Aggiorna le funzioni Node.js di prima generazione alla seconda generazione

Le app che attualmente utilizzano funzioni di prima generazione dovrebbero prendere in considerazione la migrazione alla seconda generazione seguendo le istruzioni contenute in questa guida. Le funzioni di seconda generazione utilizzano Cloud Run per fornire prestazioni migliori, migliore configurazione, migliore monitoraggio e altro ancora.

Gli esempi in questa pagina presuppongono che tu stia utilizzando JavaScript con i moduli CommonJS ( require importazioni di stile), ma gli stessi principi si applicano a JavaScript con ESM ( import … from importazioni di stile) e TypeScript.

Il processo di migrazione

Le funzioni di prima e seconda generazione possono coesistere fianco a fianco nello stesso file. Ciò consente una facile migrazione pezzo per pezzo, man mano che sei pronto. Ti consigliamo di eseguire la migrazione di una funzione alla volta, effettuando test e verifiche prima di procedere.

Verifica le versioni della CLI Firebase e firebase-function

Assicurati di utilizzare almeno Firebase CLI versione 12.00 e firebase-functions versione 4.3.0 . Qualsiasi versione più recente supporterà la 2a e la 1a generazione.

Aggiorna le importazioni

Le funzioni di seconda generazione vengono importate dal pacchetto secondario v2 nell'SDK firebase-functions . Questo diverso percorso di importazione è tutto ciò di cui la CLI Firebase ha bisogno per determinare se distribuire il codice funzione come funzione di prima o seconda generazione.

Il sottopacchetto v2 è modulare e ti consigliamo di importare solo il modulo specifico di cui hai bisogno.

Prima: 1a gen

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

Dopo: 2a gen

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

Aggiorna le definizioni dei trigger

Poiché l'SDK di seconda generazione favorisce le importazioni modulari, aggiornare le definizioni dei trigger per riflettere le importazioni modificate dal passaggio precedente.

Gli argomenti passati ai callback per alcuni trigger sono cambiati. In questo esempio, tieni presente che gli argomenti del callback onDocumentCreated sono stati consolidati in un singolo oggetto event . Inoltre, alcuni trigger dispongono di nuove comode funzionalità di configurazione, come l'opzione cors del trigger onRequest .

Prima: 1a gen

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

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

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

Dopo: 2a gen

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

Utilizza la configurazione parametrizzata

Le funzioni di seconda generazione abbandonano il supporto per functions.config a favore di un'interfaccia più sicura per definire i parametri di configurazione in modo dichiarativo all'interno della codebase. Con il nuovo modulo params , la CLI blocca la distribuzione a meno che tutti i parametri non abbiano un valore valido, garantendo che una funzione non venga distribuita con una configurazione mancante.

Migrare al sottopacchetto params

Se hai utilizzato la configurazione dell'ambiente con functions.config , puoi migrare la configurazione esistente alla configurazione con parametri .

Prima: 1a gen

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

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

  // ...
});

Dopo: 2a gen

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

  // ...
});

Impostare i valori dei parametri

La prima volta che esegui la distribuzione, la CLI di Firebase richiede tutti i valori dei parametri e salva i valori in un file dotenv. Per esportare i valori di Functions.config, esegui firebase functions:config:export .

Per maggiore sicurezza, puoi anche specificare i tipi di parametri e le regole di convalida .

Caso speciale: chiavi API

Il modulo params si integra con Cloud Secret Manager, che fornisce un controllo granulare degli accessi a valori sensibili come le chiavi API. Per ulteriori informazioni, vedere i parametri segreti .

Prima: 1a gen

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

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

Dopo: 2a gen

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

Imposta le opzioni di esecuzione

La configurazione delle opzioni di runtime è cambiata tra la 1a e la 2a generazione. La seconda generazione aggiunge anche una nuova funzionalità per impostare le opzioni per tutte le funzioni.

Prima: 1a gen

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

Dopo: 2a gen

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

Utilizzare la concorrenza

Un vantaggio significativo delle funzioni di seconda generazione è la capacità di una singola istanza di funzione di servire più di una richiesta contemporaneamente. Ciò può ridurre drasticamente il numero di avvii a freddo sperimentati dagli utenti finali. Per impostazione predefinita, la concorrenza è impostata su 80, ma puoi impostarla su qualsiasi valore compreso tra 1 e 1000:

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

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

L'ottimizzazione della concorrenza può migliorare le prestazioni e ridurre il costo delle funzioni. Scopri di più sulla concorrenza in Consentire richieste simultanee .

Controlla l'utilizzo delle variabili globali

Le funzioni di prima generazione scritte senza tenere presente la concorrenza potrebbero utilizzare variabili globali impostate e lette su ogni richiesta. Quando la concorrenza è abilitata e una singola istanza inizia a gestire più richieste contemporaneamente, ciò potrebbe introdurre bug nella funzione poiché le richieste simultanee iniziano a impostare e leggere le variabili globali contemporaneamente.

Durante l'aggiornamento, puoi impostare la CPU della tua funzione su gcf_gen1 e impostare concurrency su 1 per ripristinare il comportamento della prima generazione:

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

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

Tuttavia, questa soluzione non è consigliata a lungo termine, poiché perderebbe i vantaggi prestazionali delle funzioni di seconda generazione. Controlla invece l'utilizzo delle variabili globali nelle tue funzioni e rimuovi queste impostazioni temporanee quando sei pronto.

Migrare il traffico alle nuove funzioni di seconda generazione

Proprio come quando cambi la regione di una funzione o il tipo di trigger , dovrai assegnare un nuovo nome alla funzione di seconda generazione e migrare lentamente il traffico su di essa.

Non è possibile aggiornare una funzione dalla 1a alla 2a generazione con lo stesso nome ed eseguire firebase deploy . In questo modo si verificherà l'errore:

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

Prima di seguire questi passaggi, assicurati innanzitutto che la tua funzione sia idempotente , poiché sia ​​la nuova versione che la vecchia versione della tua funzione verranno eseguite contemporaneamente durante la modifica. Ad esempio, se disponi di una funzione di prima generazione che risponde agli eventi di scrittura in Firestore, assicurati che la risposta a una scrittura due volte, una volta tramite la funzione di prima generazione e una volta tramite la funzione di seconda generazione, in risposta a tali eventi lasci la tua app in un stato coerente.

  1. Rinominare la funzione nel codice delle funzioni. Ad esempio, rinominare resizeImage in resizeImageSecondGen .
  2. Distribuire la funzione, in modo che siano in esecuzione sia la funzione originale di prima generazione che quella di seconda generazione.
    1. Nel caso di trigger richiamabili, coda attività e HTTP, iniziare a indirizzare tutti i client alla funzione di seconda generazione aggiornando il codice client con il nome o l'URL della funzione di seconda generazione.
    2. Con i trigger in background, sia le funzioni di prima che di seconda generazione risponderanno a ogni evento immediatamente dopo la distribuzione.
  3. Una volta eseguita la migrazione di tutto il traffico, elimina la funzione di prima generazione utilizzando il comando firebase functions:delete della CLI Firebase.
    1. Facoltativamente, rinominare la funzione di seconda generazione in modo che corrisponda al nome della funzione di prima generazione.