Gestire le funzioni


Puoi eseguire il deployment, eliminare e modificare le funzioni utilizzando i comandi dell'interfaccia a riga di comando Firebase o impostando le opzioni di runtime nel codice sorgente delle funzioni.

Esegui il deployment delle funzioni

Per eseguire il deployment delle funzioni, esegui questo comando dell'interfaccia a riga di comando Firebase:

firebase deploy --only functions

Per impostazione predefinita, l'interfaccia a riga di comando Firebase esegue contemporaneamente il deployment di tutte le funzioni all'interno dell'origine. Se il progetto contiene più di cinque funzioni, ti consigliamo di utilizzare il flag --only con nomi di funzioni specifici per eseguire il deployment solo delle funzioni che hai modificato. Eseguire il deployment di funzioni specifiche in questo modo velocizza il processo di deployment e ti aiuta a evitare di superare le quote di deployment. Ad esempio:

firebase deploy --only functions:addMessage,functions:makeUppercase

Quando esegui il deployment di un numero elevato di funzioni, potresti superare la quota standard e ricevere messaggi di errore HTTP 429 o 500. Per risolvere il problema, esegui il deployment delle funzioni in gruppi di 10 o meno.

Consulta il riferimento all'interfaccia a riga di comando Firebase per l'elenco completo dei comandi disponibili.

Per impostazione predefinita, l'interfaccia a riga di comando Firebase cerca il codice sorgente nella cartella functions/. Se preferisci, puoi organizzare le funzioni in codebase o in più insiemi di file.

Elimina funzioni

Puoi eliminare le funzioni di cui è stato eseguito il deployment in precedenza nei seguenti modi:

  • Esplicitamente nell'interfaccia a riga di comando Firebase con functions:delete
  • esplicitamente nella console Google Cloud.
  • Implicitamente rimuovendo la funzione dal codice sorgente prima del deployment.

Tutte le operazioni di eliminazione richiedono una conferma prima di rimuovere la funzione dall'ambiente di produzione.

L'eliminazione esplicita delle funzioni nell'interfaccia a riga di comando Firebase supporta più argomenti nonché gruppi di funzioni e ti consente di specificare una funzione in esecuzione in una determinata regione. Inoltre, puoi ignorare la richiesta di conferma.

# Delete all functions that match the specified name in all regions.
firebase functions:delete myFunction
# Delete a specified function running in a specific region.
firebase functions:delete myFunction --region us-east-1
# Delete more than one function
firebase functions:delete myFunction myOtherFunction
# Delete a specified functions group.
firebase functions:delete groupA
# Bypass the confirmation prompt.
firebase functions:delete myFunction --force

Con l'eliminazione delle funzioni implicite, firebase deploy analizza l'origine e rimuove dalla produzione tutte le funzioni che sono state rimosse dal file.

Modifica il nome, la regione o il trigger di una funzione

Se rinomini o modifichi le regioni o l'attivatore per le funzioni che gestiscono il traffico di produzione, segui i passaggi descritti in questa sezione per evitare di perdere gli eventi durante la modifica. Prima di seguire questi passaggi, assicurati che la funzione sia idempotente, poiché la nuova versione e la vecchia versione della funzione verranno eseguite contemporaneamente durante la modifica.

Rinominare una funzione

Per rinominare una funzione, crea una nuova versione rinominata della funzione nell'origine, quindi esegui due comandi di deployment separati. Il primo comando esegue il deployment della funzione appena denominata e il secondo rimuove la versione di cui è stato eseguito il deployment in precedenza. Ad esempio, se hai un webhook attivato tramite HTTP che vuoi rinominare, rivedi il codice come segue:

Node.js

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

exports.webhook = onRequest((req, res) => {
    res.send("Hello");
});

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

exports.webhookNew = onRequest((req, res) => {
    res.send("Hello");
});

Python

# before
from firebase_functions import https_fn

@https_fn.on_request()
def webhook(req: https_fn.Request) -> https_fn.Response:
    return https_fn.Response("Hello world!")

# after
from firebase_functions import https_fn

@https_fn.on_request()
def webhook_new(req: https_fn.Request) -> https_fn.Response:
    return https_fn.Response("Hello world!")

Quindi esegui questi comandi per eseguire il deployment della nuova funzione:

# Deploy new function
firebase deploy --only functions:webhookNew

# Wait until deployment is done; now both functions are running

# Delete webhook
firebase functions:delete webhook

Modificare la regione o le regioni di una funzione

Se stai modificando le regioni specificate per una funzione che gestisce il traffico di produzione, puoi evitare la perdita di eventi svolgendo i seguenti passaggi in ordine:

  1. Rinomina la funzione e modifica la regione o le regioni in base alle tue esigenze.
  2. Esegui il deployment della funzione rinominata, in modo da eseguire temporaneamente lo stesso codice in entrambi i set di regioni.
  3. Elimina la funzione precedente.

Ad esempio, se hai una funzione attivata da Cloud Firestore che si trova attualmente nella regione delle funzioni predefinite di us-central1 e vuoi eseguirne la migrazione a asia-northeast1, devi prima modificare il codice sorgente per rinominare la funzione e rivedere la regione.

Node.js

// before
exports.firestoreTrigger = onDocumentCreated(
  "my-collection/{docId}",
  (event) => {},
);

// after
exports.firestoreTriggerAsia = onDocumentCreated(
  {
    document: "my-collection/{docId}",
    region: "asia-northeast1",
  },
  (event) => {},
);

Il codice aggiornato deve specificare il filtro eventi corretto (in questo caso document) insieme alla regione. Per ulteriori informazioni, consulta la sezione sulle località di Cloud Functions.

Python

# Before
@firestore_fn.on_document_created("my-collection/{docId}")
def firestore_trigger(event):
    pass

# After
@firestore_fn.on_document_created("my-collection/{docId}",
                                  region="asia-northeast1")
def firestore_trigger_asia(event):
    pass

Poi esegui il deployment eseguendo:

firebase deploy --only functions:firestoreTriggerAsia

Ora sono in esecuzione due funzioni identiche: firestoreTrigger è in esecuzione in us-central1 e firestoreTriggerAsia è in esecuzione in asia-northeast1.

Poi elimina firestoreTrigger:

firebase functions:delete firestoreTrigger

Ora esiste una sola funzione, firestoreTriggerAsia, che viene eseguita in asia-northeast1.

Modificare il tipo di attivatore di una funzione

Man mano che sviluppi il tuo deployment di Cloud Functions for Firebase nel tempo, potresti dover cambiare il tipo di attivatore di una funzione per vari motivi. Ad esempio, potresti voler passare da un tipo di evento Firebase Realtime Database o Cloud Firestore a un altro tipo.

Non è possibile modificare il tipo di evento di una funzione semplicemente modificando il codice sorgente ed eseguendo firebase deploy. Per evitare errori, modifica il tipo di trigger di una funzione seguendo questa procedura:

  1. Modifica il codice sorgente in modo da includere una nuova funzione con il tipo di trigger desiderato.
  2. Eseguire il deployment della funzione, in modo da eseguire temporaneamente sia la vecchia che la nuova funzione.
  3. Elimina in modo esplicito la funzione precedente dall'ambiente di produzione utilizzando l'interfaccia a riga di comando Firebase.

Ad esempio, se avevi una funzione che è stata attivata al momento dell'eliminazione di un oggetto, ma poi hai abilitato il controllo delle versioni degli oggetti e vuoi invece sottoscrivere l'evento di archiviazione, prima rinomina la funzione e modificala in modo che abbia il nuovo tipo di trigger.

Node.js

// before
const {onObjectDeleted} = require("firebase-functions/v2/storage");

exports.objectDeleted = onObjectDeleted((event) => {
    // ...
});

// after
const {onObjectArchived} = require("firebase-functions/v2/storage");

exports.objectArchived = onObjectArchived((event) => {
    // ...
});

Python

# before
from firebase_functions import storage_fn

@storage_fn.on_object_deleted()
def object_deleted(event):
  # ...

# after 
from firebase_functions import storage_fn

@storage_fn.on_object_archived()
def object_archived(event):
  # ...

Quindi, esegui i seguenti comandi per creare prima la nuova funzione, prima di eliminare la vecchia:

# Create new function objectArchived
firebase deploy --only functions:objectArchived

# Wait until deployment is done; now both objectDeleted and objectArchived are running

# Delete objectDeleted
firebase functions:delete objectDeleted

Impostare le opzioni di runtime

Cloud Functions for Firebase ti consente di selezionare opzioni di runtime come la versione del runtime Node.js, il timeout per funzione, l'allocazione della memoria e le istanze di funzione minime/massime.

Come best practice, queste opzioni (tranne la versione di Node.js) devono essere impostate su un oggetto di configurazione all'interno del codice della funzione. Questo oggetto RuntimeOptions è la fonte attendibile per le opzioni di runtime della funzione e sostituisce le opzioni impostate tramite qualsiasi altro metodo (ad esempio tramite la console Google Cloud o gcloud CLI).

Se il flusso di lavoro di sviluppo prevede l'impostazione manuale delle opzioni di runtime tramite la console Google Cloud o gcloud CLI e non vuoi che questi valori vengano sostituiti a ogni deployment, imposta l'opzione preserveExternalChanges su true. Se questa opzione è impostata su true, Firebase unisce le opzioni di runtime impostate nel tuo codice con le impostazioni della versione attualmente di cui è stato eseguito il deployment della funzione con la seguente priorità:

  1. L'opzione è impostata nel codice delle funzioni: override delle modifiche esterne.
  2. L'opzione è impostata su RESET_VALUE nel codice delle funzioni: sostituisci le modifiche esterne con il valore predefinito.
  3. L'opzione non è impostata nel codice delle funzioni, ma è impostata nella funzione attualmente di cui è stato eseguito il deployment: utilizza l'opzione specificata nella funzione di cui è stato eseguito il deployment.

L'utilizzo dell'opzione preserveExternalChanges: true è sconsigliato per la maggior parte degli scenari perché il codice non sarà più la fonte di verità completa per le opzioni di runtime per le funzioni. Se lo utilizzi, controlla la console Google Cloud o utilizza l'interfaccia a riga di comando gcloud per visualizzare la configurazione completa di una funzione.

Imposta la versione di Node.js

L'SDK Firebase per Cloud Functions consente di selezionare il runtime di Node.js. Puoi scegliere di eseguire tutte le funzioni di un progetto esclusivamente nell'ambiente di runtime corrispondente a una di queste versioni di Node.js supportate:

  • Node.js 22 (anteprima)
  • Node.js 20
  • Node.js 18

Le versioni 14 e 16 di Node.js sono deprecate e verranno ritirate all'inizio del 2025. Il deployment con queste versioni deprecate è disabilitato.

Per impostare la versione Node.js:

Puoi impostare la versione nel campo engines del file package.json creato nella directory functions/ durante l'inizializzazione. Ad esempio, per utilizzare solo la versione 18, modifica questa riga in package.json:

  "engines": {"node": "20"}

Se utilizzi il gestore dei pacchetti Yarn o hai altri requisiti specifici per il campo engines, puoi impostare il runtime per l'SDK Firebase per Cloud Functions in firebase.json:

  {
    "functions": {
      "runtime": "nodejs18" // or nodejs20
    }
  }

La CLI utilizza il valore impostato in firebase.json in preferenza a qualsiasi valore o intervallo impostato separatamente in package.json.

Esegui l'upgrade del runtime Node.js

Per eseguire l'upgrade del runtime Node.js:

  1. Assicurati che il progetto sia nel piano tariffario Blaze.
  2. Assicurati di utilizzare Firebase CLI versione 11.18.0 o successive.
  3. Modifica il valore engines nel file package.json creato nella directory functions/ durante l'inizializzazione. Ad esempio, se stai eseguendo l'upgrade dalla versione 18 alla versione 20, la voce dovrebbe essere simile alla seguente: "engines": {"node": "20"}
  4. Se vuoi, puoi testare le modifiche utilizzando Firebase Local Emulator Suite.
  5. Esegui di nuovo il deployment di tutte le funzioni.

Imposta versione Python

L'SDK Firebase per Cloud Functions nelle versioni 12.0.0 e successive consente di selezionare il runtime di Python. Imposta la versione del runtime in firebase.json come mostrato:

  {
    "functions": {
      "runtime": "python310" // or python311
    }
  }

Controlla il comportamento di scalabilità

Per impostazione predefinita, Cloud Functions for Firebase scala il numero di istanze in esecuzione in base al numero di richieste in entrata, riducendo potenzialmente il numero di istanze a zero in periodi di traffico ridotto. Tuttavia, se la tua app richiede una latenza ridotta e vuoi limitare il numero di avvii a freddo, puoi modificare questo comportamento predefinito specificando un numero minimo di istanze di container da mantenere in uso e pronte per gestire le richieste.

Allo stesso modo, puoi impostare un numero massimo per limitare la scalabilità delle istanze in risposta alle richieste in entrata. Utilizza questa impostazione per controllare i costi o per limitare il numero di connessioni a un servizio di supporto, ad esempio a un database.

Utilizzando queste impostazioni insieme all'impostazione di contemporaneità per istanza (nuova nella 2ª generazione), puoi controllare e ottimizzare il comportamento di scalabilità per le tue funzioni. La natura dell'applicazione e della funzione determinerà quali impostazioni sono più convenienti e produrranno il rendimento migliore.

Per alcune app con traffico ridotto, è ottimale un'opzione con meno CPU, senza più contemporaneità. Per altri casi in cui gli avvii a freddo sono un problema critico, l'impostazione di un numero minimo di istanze e di un'elevata contemporaneità significa che un insieme di istanze viene sempre mantenuto attivo per gestire grandi picchi di traffico.

Per le app di dimensioni ridotte che ricevono pochissimo traffico, l'impostazione di un numero massimo di istanze ridotto con una concorrenza elevata consente all'app di gestire picchi di traffico senza costi eccessivi. Tuttavia, tieni presente che se il numero di istanze massime è impostato su un valore troppo basso, le richieste potrebbero essere ignorate quando viene raggiunto il limite.

Consenti richieste in parallelo

In Cloud Functions for Firebase (1a generazione), ogni istanza poteva gestire una richiesta alla volta, quindi il comportamento di scalabilità era impostato solo con le impostazioni del numero minimo e massimo di istanze. Oltre a controllare il numero di istanze, in Cloud Functions for Firebase (2ª gen.) puoi controllare il numero di richieste che ogni istanza può gestire contemporaneamente con l'opzione concurrency. Il valore predefinito per la contemporaneità è 80, ma puoi impostarlo su qualsiasi numero intero compreso tra 1 e 1000.

Le funzioni con impostazioni di contemporaneità più elevate possono assorbire picchi di traffico senza avvio a freddo, poiché è probabile che ogni istanza abbia un certo margine di miglioramento. Se un'istanza è configurata per gestire fino a 50 richieste simultanee, ma al momento ne gestisce solo 25, può gestire un picco di 25 richieste aggiuntive senza richiedere il cold start di una nuova istanza. Al contrario, con un'impostazione di contemporaneità di appena 1, il picco delle richieste potrebbe portare a 25 avvii a freddo.

Questo scenario semplificato dimostra i potenziali aumenti dell'efficienza della contemporaneità. In realtà, il comportamento di scalabilità per ottimizzare l'efficienza e ridurre le avviamenti a freddo con la concorrenza è più complesso. La concorrenza in Cloud Functions for Firebase 2ª gen. è basata su Cloud Run e segue le regole di Cloud Run per la scalabilità automatica delle istanze di container.

Quando fai esperimenti con impostazioni di contemporaneità più elevate in Cloud Functions for Firebase (2a generazione), tieni presente quanto segue:

  • Impostazioni di contemporaneità più elevate possono richiedere CPU e RAM maggiori per prestazioni ottimali fino a raggiungere un limite pratico. Una funzione che esegue un'elaborazione intensiva di immagini o video, ad esempio, potrebbe non disporre delle risorse per gestire 1000 richieste in parallelo, anche quando le impostazioni di CPU e RAM sono ottimizzate.
  • Poiché Cloud Functions for Firebase (2a generazione) si basa su Cloud Run, puoi consultare anche le indicazioni di Google Cloud per l'ottimizzazione della contemporaneità.
  • Assicurati di testare a fondo la multicontemporaneità in un ambiente di test prima di passare alla multicontemporaneità in produzione.

Mantieni attive un numero minimo di istanze

Puoi impostare un numero minimo di istanze per una funzione nel codice sorgente. Ad esempio, questa funzione imposta un minimo di 5 istanze da mantenere attive:

Node.js

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

exports.getAutocompleteResponse = onCall(
  {
    // Keep 5 instances warm for this latency-critical function
    minInstances: 5,
  },
  (event) => {
    // Autocomplete user’s search term
  }
);

Python

@https_fn.on_call(min_instances=5)
def get_autocomplete_response(event: https_fn.CallableRequest) -> https_fn.Response:

Ecco alcuni aspetti da considerare quando si imposta un valore minimo per le istanze:

  • Se Cloud Functions for Firebase scala la tua app oltre l'impostazione, rispetterà un avvio a freddo per ogni istanza al di sopra di questa soglia.
  • Gli avvii a freddo hanno l'effetto più grave sulle app con traffico irregolare. Se la tua app presenta picchi di traffico e imposti un valore sufficientemente elevato da ridurre le avviamenti a freddo a ogni aumento del traffico, noterai una latenza notevolmente ridotta. Per le app con traffico costante, è improbabile che gli avvii a freddo influiscano negativamente sulle prestazioni.
  • L'impostazione del numero minimo di istanze può avere senso per gli ambienti di produzione, ma in genere è consigliabile evitarla negli ambienti di test. Per scalare fino a zero nel progetto di test, ma ridurre comunque gli avvii a freddo nel progetto di produzione, puoi impostare un valore minimo delle istanze nella configurazione parametrizzata:

    Node.js

    const functions = require('firebase-functions/v1');
    const { defineInt, defineString } = require('firebase-functions/params');
    
    // Define some parameters
    const minInstancesConfig = defineInt('HELLO_WORLD_MININSTANCES');
    const welcomeMessage = defineString('WELCOME_MESSAGE');
    
    // To use configured parameters inside the config for a function, provide them 
    // directly. To use them at runtime, call .value() on them.
    export const helloWorld = functions.runWith({ minInstances: minInstancesConfig}).https.onRequest(
      (req, res) => {
        res.send(`${welcomeMessage.value()}! I am a function.`);
      }
    );
    

    Python

    MIN_INSTANCES = params.IntParam("HELLO_WORLD_MININSTANCES")
    WELCOME_MESSAGE = params.StringParam("WELCOME_MESSAGE")
    
    @https_fn.on_request(min_instances=MIN_INSTANCES.value())
    def get_autocomplete_response(event: https_fn.Request) -> https_fn.Response:
        return https_fn.Response(f"{WELCOME_MESSAGE.value()} I'm a function.")
    

Limitare il numero massimo di istanze per una funzione

Puoi impostare un valore per le istanze massime nel codice sorgente della funzione. Ad esempio, questa funzione imposta un limite di 100 istanze per non superare un ipotetico database legacy:

Node.js

const { onMessagePublished } = require("firebase-functions/v2/pubsub");

exports.mirrorevents = onMessagePublished(
  { topic: "topic-name", maxInstances: 100 },
  (event) => {
    // Connect to legacy database
  }
);

Python

@pubsub_fn.on_message_published(topic="topic-name", max_instances=100)
def mirrorevents(event: pubsub_fn.CloudEvent):
#  Connect to legacy database

Se una funzione HTTP viene scalata fino al limite massimo di istanze, le nuove richieste vengono messe in coda per 30 secondi e poi rifiutate con un codice di risposta 429 Too Many Requests se non è disponibile alcuna istanza entro questo periodo di tempo.

Per scoprire di più sulle best practice per l'utilizzo delle impostazioni relative al numero massimo di istanze, consulta queste best practice per l'impostazione del numero massimo di istanze.

Impostare il timeout e l'allocazione della memoria

In alcuni casi, le funzioni possono avere requisiti speciali per un valore di timeout lungo o un'allocazione di memoria elevata. Puoi impostare questi valori nella console Google Cloud o nel codice sorgente della funzione (solo Firebase).

Per impostare l'allocazione della memoria e il timeout nel codice sorgente delle funzioni, utilizza le opzioni globali per la memoria e i secondi di timeout per personalizzare la macchina virtuale che esegue le funzioni. Ad esempio, questa funzione Cloud Storage utilizza 1 GB di memoria e termina il tempo di esecuzione dopo 300 secondi:

Node.js

exports.convertLargeFile = onObjectFinalized({
  timeoutSeconds: 300,
  memory: "1GiB",
}, (event) => {
  // Do some complicated things that take a lot of memory and time
});

Python

@storage_fn.on_object_finalized(timeout_sec=300, memory=options.MemoryOption.GB_1)
def convert_large_file(event: storage_fn.CloudEvent):
# Do some complicated things that take a lot of memory and time.

Il valore massimo per i secondi di timeout è 540, ovvero 9 minuti.

Per impostare l'allocazione della memoria e il timeout nella console Google Cloud:

  1. Nella console Google Cloud, seleziona Cloud Functions for Firebase dal menu a sinistra.
  2. Seleziona una funzione facendo clic sul relativo nome nell'elenco delle funzioni.
  3. Fai clic sull'icona Modifica nel menu in alto.
  4. Seleziona un'allocazione della memoria dal menu a discesa con l'etichetta Memoria allocata.
  5. Fai clic su Altro per visualizzare le opzioni avanzate e inserisci un numero di secondi nella casella di testo Timeout.
  6. Fai clic su Salva per aggiornare la funzione.

Sostituisci le impostazioni predefinite della CPU

Fino a 2 GB di memoria allocata, ogni funzione in Cloud Functions for Firebase (2ª gen.) è predefinita su una CPU, che poi aumenta a 2 CPU per 4 e 8 GB. Tieni presente che questo è molto diverso dal comportamento predefinito della 1ª gen. in modi che potrebbero generare costi leggermente più elevati per le funzioni a bassa memoria, come indicato nella seguente tabella:

RAM allocata CPU predefinita della versione 1 (frazione) CPU predefinita della versione 2 Aumento di prezzo per ms
128 MB 12/1 1 10,5x
256 MB 6/1 1 5,3x
512 MB 1/3 1 2,7x
1 GB 12/7 1 1,6 volte
2 GB 1 1 1x
4 GB 2 2 1x
8 GB 2 2 1x
16 GB n/d 4 n/d

Se preferisci il comportamento della 1ª gen. per le funzioni di 2ª gen., imposta i valori predefiniti della 1ª gen. come opzione globale:

Node.js

// Turn off Firebase defaults
setGlobalOptions({ cpu: 'gcf_gen1' });

Python

# Use 1st gen behavior
set_global_options(cpu="gcf_gen1")

Per le funzioni che richiedono un'elevata intensità di risorse CPU, la 2ª generazione offre la flessibilità di configurare un'altra CPU. Puoi aumentare la CPU in base alla funzione, come mostrato di seguito:

Node.js

// Boost CPU in a function:
export const analyzeImage = onObjectFinalized({ cpu: 2 }, (event) => {
  // computer vision goes here
});

Python

# Boost CPU in a function:
@storage_fn.on_object_finalized(cpu=2)
def analyze_image(event: storage_fn.CloudEvent):
# computer vision goes here