Le app che utilizzano funzioni di 1ª gen. devono valutare la migrazione alla 2ª gen. seguendo le istruzioni riportate in questa guida. Le funzioni di 2ª gen. utilizzano Cloud Run per fornire prestazioni, configurazione, monitoraggio e altro ancora migliori.
Gli esempi in questo documento presuppongono che tu stia utilizzando JavaScript con i moduli CommonJS (importazioni in stile require), ma gli stessi principi si applicano a JavaScript con ESM (importazioni in stile import … from) e TypeScript.
Il processo di migrazione
Le funzioni di 1ª gen. e 2ª gen. possono coesistere nello stesso file di origine. In questo modo puoi eseguire la migrazione della codebase un pezzo alla volta, quando è tutto pronto. Tuttavia, tieni presente che questa combinazione di pacchetti non funziona all'interno di una singola funzione discreta.
Ti consigliamo di eseguire la migrazione di una funzione alla volta, eseguendo test e verifiche prima di procedere.
Verifica le versioni dell'interfaccia a riga di comando Firebase e di firebase-functions
Assicurati di utilizzare almeno la versione 12.00 dell'interfaccia a riga di comando Firebase e la versione 4.3.0 di firebase-functions. Qualsiasi versione più recente supporterà sia la 1ª gen. sia la 2ª gen.
Aggiorna importazioni
Le funzioni di 2ª gen. vengono importate dal sottopacchetto v2 nell'SDK firebase-functions. Questo percorso di importazione diverso è tutto ciò di cui la CLI Firebase ha bisogno per determinare se eseguire il deployment del codice della funzione come funzione di 1ª o 2ª gen.
Il sottopacchetto v2 è modulare e ti consigliamo di importare solo il modulo specifico di cui hai bisogno.
Prima: 1ª gen.
const functions = require("firebase-functions/v1");
Dopo: 2ª 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 2ª generazione preferisce le importazioni modulari, aggiorna le definizioni dei trigger in modo che riflettano le importazioni modificate del passaggio precedente.
Gli argomenti passati ai callback per alcuni trigger sono stati modificati. In questo esempio, tieni presente che gli argomenti del callback onDocumentCreated sono stati consolidati in un unico oggetto event. Inoltre, alcuni trigger dispongono di nuove e pratiche funzionalità di configurazione, come l'opzione cors del trigger onRequest.
Prima: 1ª gen.
const functions = require("firebase-functions/v1");
exports.date = functions.https.onRequest((req, res) => {
// ...
});
exports.uppercase = functions.firestore
.document("my-collection/{docId}")
.onCreate((change, context) => {
// ...
});
Dopo: 2ª 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) => {
/* ... */
});
Riduci al minimo gli sforzi di riscrittura con la destrutturazione di JavaScript
Se le tue funzioni hanno corpi complessi che si basano molto sul contesto di 1ª gen. o su parametri specifici del provider (come message o snapshot), puoi utilizzare gli helper di compatibilità di 1ª gen. integrati nell'SDK di 2ª gen.
L'SDK di 2ª gen. applica automaticamente patch all'oggetto evento con getter che corrispondono alle firme di 1ª gen. In questo modo puoi utilizzare la destrutturazione di JavaScript per estrarre queste proprietà direttamente nella firma del gestore, riducendo al minimo la necessità di riscrivere la logica della funzione.
Riferimento per la mappatura dei provider
| Provider | Argomenti di 1ª gen. | Destrutturazione degli eventi con patch di 2ª generazione |
| Pub/Sub | (message, context)
|
({ message, context }) => { ... }
|
| Cloud Firestore | (snapshot, context)
|
({ snapshot, context }) => { ... }
|
| Cloud Storage | (object, context)
|
({ object, context }) => { ... }
|
| Realtime Database | (snapshot, context)
|
({ snapshot, context }) => { ... }
|
| Remote Config | (version, context)
|
({ version, context }) => { ... }
|
| Cloud Scheduler | (context)
|
({ context }) => { ... }
|
| Coda di attività | (data, context)
|
({ data, context }) => { ... }
|
Prima (1ª gen.):
export const myPubSubV1 = functions.pubsub.topic("my-topic").onPublish((message, context) => {
const data = message.json;
const eventId = context.eventId;
// ... rest of the logic
});
Nuova alternativa (2ª gen. con destrutturazione):
import { onMessagePublished } from "firebase-functions/v2/pubsub";
export const myPubSubV2 = onMessagePublished("my-topic", ({ message, context }) => {
// No need to change the function body!
const data = message.json; // Uses v1 Message wrapper
const eventId = context.eventId; // Uses v1 EventContext map
// ... rest of the logic
});
Utilizza la configurazione parametrizzata
Le funzioni di 2ª gen. non supportano più 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, l'interfaccia a riga di comando blocca il deployment a meno che tutti i parametri non abbiano un valore valido, garantendo che non venga eseguito il deployment di una funzione con una configurazione mancante.
Prima: 1ª gen.
const functions = require("firebase-functions/v1");
exports.getQuote = functions.https.onRequest(async (req, res) => {
const quote = await fetchMotivationalQuote(functions.config().apiKey);
// ...
});
Dopo: 2ª 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());
// ...
}
);
Se hai una configurazione dell'ambiente esistente con functions.config, esegui la migrazione di questa configurazione nell'ambito dell'upgrade alla 2ª gen.
L'API functions.config è deprecata e verrà ritirata a marzo 2027.
Dopo questa data, i deployment con functions.config non andranno a buon fine.
Per evitare errori di deployment, esegui la migrazione della configurazione a Cloud Secret Manager utilizzando l'interfaccia a riga di comando Firebase. Questa opzione è vivamente consigliata in quanto rappresenta il modo più efficiente e sicuro per eseguire la migrazione della configurazione.
Esporta la configurazione con l'interfaccia a riga di comando Firebase
Utilizza il comando
config exportper esportare la configurazione dell'ambiente esistente in un nuovo secret in 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```Aggiorna il codice della funzione per associare i secret
Per utilizzare la configurazione archiviata nel nuovo secret in Secret Manager di Cloud, utilizza l'API
defineJsonSecretnell'origine della funzione. Inoltre, assicurati che i secret siano associati a tutte le funzioni che ne hanno bisogno.Prima
const functions = require("firebase-functions/v1"); exports.myFunction = functions.https.onRequest((req, res) => { const apiKey = functions.config().someapi.key; // ... });Dopo
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; // ... });Esegui il deployment delle funzioni
Esegui il deployment delle funzioni aggiornate per applicare le modifiche e associare le autorizzazioni per i secret.
firebase deploy --only functions:<your-function-name>
Imposta le opzioni di runtime
La configurazione delle opzioni di runtime è cambiata tra la 1ª e la 2ª gen. La 2ª gen. aggiunge anche una nuova funzionalità per impostare le opzioni per tutte le funzioni.
Prima: 1ª gen.
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) => {
// ...
});
Dopo: 2ª 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) => {
/* ... */
});
Aggiorna il service account predefinito (facoltativo)
Mentre le funzioni di 1ª gen. utilizzano il service account predefinito Google App Engine per autorizzare l'accesso alle API Firebase, le funzioni di 2ª gen. utilizzano il service account predefinito Compute Engine. Questa differenza può causare problemi di autorizzazione per le funzioni di cui è stata eseguita la migrazione alla 2ª gen. nei casi in cui hai concesso autorizzazioni speciali al service account di 1ª gen. Se non hai modificato le autorizzazioni del service account, puoi saltare questo passaggio.
La soluzione consigliata è assegnare esplicitamente il service account predefinito App Engine di 1ª gen. esistente alle funzioni di cui vuoi eseguire la migrazione alla 2ª gen., eseguendo l'override del valore predefinito della 2ª gen. Per farlo, assicurati che ogni funzione di cui è stata eseguita la migrazione imposti il valore corretto per 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) => {
// ...
});
In alternativa, puoi assicurarti di modificare i dettagli del service account in modo che corrispondano a tutte le autorizzazioni necessarie sia per il service account predefinito App Engine (per la 1ª gen.) sia per il service account predefinito Compute Engine (per la 2ª gen.).
Utilizza la concorrenza
Un vantaggio significativo delle funzioni di 2ª gen. è la capacità di una singola istanza di funzione di gestire più di una richiesta alla volta. In questo modo, è possibile ridurre drasticamente il numero di avvii a freddo riscontrati 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 contemporaneità può migliorare le prestazioni e ridurre i costi delle funzioni. Scopri di più sulla contemporaneità in Consenti richieste in parallelo.
Controlla l'utilizzo delle variabili globali
Le funzioni di 1ª gen. scritte senza tenere conto della concorrenza potrebbero utilizzare variabili globali impostate e lette per ogni richiesta. Quando la concorrenza è abilitata e una singola istanza inizia a gestire più richieste contemporaneamente, potrebbero verificarsi bug nella funzione, poiché le richieste in parallelo iniziano a impostare e leggere le variabili globali contemporaneamente.
Durante l'upgrade, puoi impostare la CPU della funzione su gcf_gen1 e impostare concurrency su 1 per ripristinare il comportamento di 1ª gen.:
const {onRequest} = require("firebase-functions/v2/https");
exports.date = onRequest({
// TEMPORARY FIX: remove concurrency
cpu: "gcf_gen1",
concurrency: 1
},
(req, res) => {
// ...
});
Tuttavia, questa non è una soluzione consigliata a lungo termine, perché rinuncia ai vantaggi in termini di prestazioni delle funzioni di 2ª gen. Controlla invece l'utilizzo delle variabili globali nelle tue funzioni e rimuovi queste impostazioni temporanee quando è tutto pronto.
Esegui la migrazione del traffico alle nuove funzioni di 2ª gen.
Come quando modifichi la regione o il tipo di trigger di una funzione, devi assegnare un nuovo nome alla funzione di 2ª gen ed eseguire lentamente la migrazione del traffico.
Non è possibile eseguire l'upgrade di una funzione dalla 1ª alla 2ª gen. con lo stesso nome
e lo stesso runtime firebase deploy. In questo modo verrà generato l'errore:
Upgrading from GCFv1 to GCFv2 is not yet supported. Please delete your old function or wait for this feature to be ready.
La strategia di migrazione dipende dal tipo di trigger utilizzato dalla funzione.
Esegui la migrazione dei trigger Callable, coda di attività e HTTP
Questi trigger sono chiamate dirette. Poiché la funzione di 2ª gen. avrà un nuovo nome (e un nuovo URL per i trigger HTTP), puoi eseguire la migrazione del traffico aggiornando i client.
- Rinomina la funzione nel codice (ad esempio, rinomina
myCallableinmyCallableV2). - Eseguire il deployment della funzione. Le funzioni di 1ª gen. e di 2ª gen. sono ora in esecuzione.
- Aggiorna il codice client o il chiamante in modo che punti al nome o all'URL della nuova funzione di Cloud Functions (2nd gen).
- Una volta che tutto il traffico è stato spostato alla nuova funzione, elimina la funzione di 1ª gen. utilizzando il comando
firebase functions:deletedell'interfaccia a riga di comando Firebase.
Esegui la migrazione dei trigger in background
I trigger in background (come i trigger Pub/Sub, Cloud Firestore e Cloud Storage) rispondono agli eventi nel tuo progetto. Per evitare di perdere eventi durante la transizione, devi eseguire temporaneamente le funzioni di 1ª gen. e di 2ª gen. in parallelo.
Durante il periodo di transizione, entrambe le funzioni verranno attivate dallo stesso evento. Ciò significa che la logica di business verrà eseguita due volte per evento. Prima di procedere, assicurati che la funzione sia idempotente.
Aggiungi la funzione di 2ª gen. accanto alla funzione di 1ª gen., mantenendo la funzione di 1ª gen. esistente nel codice e aggiungendo la funzione di 2ª gen. in ascolto della stessa origine evento.
import * as functions from "firebase-functions/v1"; import { onMessagePublished } from "firebase-functions/v2/pubsub"; // --- Existing 1st gen function --- export const myPubSub = functions.pubsub.topic("my-topic").onPublish((message, context) => { console.log("V1 handler running for event:", context.eventId); // ... existing v1 function logic ... }); // --- New v2 passthrough function --- export const myPubSubV2 = onMessagePublished("my-topic", async ({ message, context }) => { console.log("v2 handler triggering V1 for event:", context.eventId); // Call the v1 function's handler await myPubSub.run(message, context); });Esegui
firebase deploy. Entrambe le funzioni sono ora attive e ascoltano gli stessi eventi.Verifica che la funzione di 2ª gen. riceva traffico. Monitora i log per entrambe le funzioni. Assicurati che la funzione di 2ª generazione venga richiamata per tutti gli eventi e che le chiamate vadano a buon fine.
Quando hai la certezza che la funzione venga eseguita correttamente, sposta la logica di business effettiva dalla funzione di 1ª gen. al corpo della funzione di 2ª gen. Se hai utilizzato il metodo passthrough, rimuovi la chiamata a
myPubSub.run().import * as functions from "firebase-functions/v1"; import { onMessagePublished } from "firebase-functions/v2/pubsub"; // --- Existing v1 function (to be removed next) --- export const myPubSub = functions.pubsub.topic("my-topic").onPublish((message, context) => { console.log("v1 handler running for event:", context.eventId); // ... existing v1 function logic ... }); // --- New v2 function with full logic --- export const myPubSubV2 = onMessagePublished("my-topic", ({ message, context }) => { console.log("v2 handler running for event:", context.eventId); // ... existing v1 function logic WAS MOVED HERE ... });Esegui il deployment di questa modifica.
Rimuovi la definizione della funzione di 1ª gen. dal codice ed esegui nuovamente il deployment. La CLI ti chiederà di eliminare la funzione di 1ª gen. da Google Cloud.