Estendi con le funzioni di Cloud Run (2ª generazione)

Con le funzioni Cloud Run, puoi eseguire il deployment del codice per gestire gli eventi attivati da modifiche nel database Firestore. Ciò ti consente di aggiungere funzionalità lato server senza utilizzare i tuoi server.

Estendi Firestore con le funzioni di Cloud Run (2ª generazione)

Le funzioni Cloud Run (2ª generazione) supportano il seguente evento Firestore che ti consentono di creare gestori legati agli eventi Firestore:

Tipo di evento Trigger
google.cloud.firestore.document.v1.created Si attiva quando un documento viene scritto per la prima volta.
google.cloud.firestore.document.v1.updated Viene attivato quando esiste già un documento e un valore è stato modificato.
google.cloud.firestore.document.v1.deleted Si attiva quando un documento viene eliminato.
google.cloud.firestore.document.v1.written Si attiva quando vengono attivati created, updated o deleted.
google.cloud.firestore.document.v1.created.withAuthContext Uguale a created, ma con l'aggiunta delle informazioni di autenticazione.
google.cloud.firestore.document.v1.updated.withAuthContext Come updated, ma aggiunge le informazioni di autenticazione.
google.cloud.firestore.document.v1.deleted.withAuthContext Uguale a deleted, ma con l'aggiunta delle informazioni di autenticazione.
google.cloud.firestore.document.v1.written.withAuthContext Uguale a written, ma con l'aggiunta delle informazioni di autenticazione.

Solo trigger di eventi Firestore sulle modifiche ai documenti. Un aggiornamento a un documento Firestore in cui i dati non è modificato (una scrittura autonoma) non genera un evento di aggiornamento o scrittura. È impossibile aggiungere eventi a campi specifici.

Includi il contesto di autenticazione nell'evento

Per includere ulteriori informazioni di autenticazione sull'evento, utilizza un attivatore dell'evento con l'estensione withAuthContext. Questa estensione aggiunge altre e informazioni sull'entità che ha attivato l'evento. Aggiunge Attributi authtype e authid oltre alle informazioni restituite in l'evento di base. Consulta le authcontext Riferimento per ulteriori informazioni sui valori degli attributi.

Scrivi una funzione attivata da Firestore

Per scrivere una funzione che risponda agli eventi Firestore, preparati a specificare quanto segue durante il deployment:

  • un tipo di evento trigger
  • un filtro di eventi di trigger per selezionare i documenti associati alla funzione
  • il codice della funzione da eseguire

Filtri degli eventi di trigger

Quando specifichi un filtro eventi, puoi indicare un documento esatto una corrispondenza o un pattern del percorso. Utilizza un pattern del percorso per associare più documenti a caratteri jolly, * o **.

Ad esempio, puoi rispondere alle modifiche al seguente documento:

users/marie

Utilizza i caratteri jolly, * o **, per rispondere alle modifiche nei documenti che corrispondono a uno schema. Un carattere jolly * corrisponde a un singolo segmento e un carattere jolly a più segmenti ** corrisponde a zero o più segmenti nel pattern.

Per le corrispondenze di singoli segmenti (*), puoi anche utilizzare un gruppo di acquisizione denominato. Ad esempio, users/{userId}.

Ad esempio:

Pattern Descrizione
/users/* o /users/{userId} Corrisponde a tutti i documenti nella raccolta /users. Non corrisponde ai documenti in raccolte secondarie come /users/marie/messages/33e2IxYBD9enzS50SJ68
/users/** Corrisponde a tutti i documenti nella raccolta /users e ai documenti in sottoraccolte come /users/marie/messages/33e2IxYBD9enzS50SJ68

Per scoprire di più sui pattern di percorso, consulta Pattern di percorso Eventarc.

L'attivatore deve sempre puntare a un documento, anche se usi un carattere jolly. Ad esempio, users/{userId=*}/{messageCollectionId=*} non è valido perché {messageCollectionId=*} è una raccolta. Tuttavia, users/{userId=*}/{messageCollectionId}/{messageId=*} è valida perché {messageId=*} rimanderà sempre a un documento.

Funzioni di esempio

L'esempio seguente mostra come ricevere eventi Firestore. Per lavorare con i dati dei documenti coinvolti in un evento, consulta i value e old_value campi.

  • value: un oggetto Document contenente un'istantanea documento post-operazione. Questo campo non viene compilato per gli eventi di eliminazione.
  • old_value: un oggetto Document che contiene un documento di pre-operazione senza dover creare uno snapshot. Questo campo viene compilato solo per gli eventi di aggiornamento ed eliminazione.

Go

Per eseguire l'autenticazione su Firestore, configura le credenziali predefinite dell'applicazione. Per ulteriori informazioni, consulta Configurare l'autenticazione per un ambiente di sviluppo locale.


// Package hellofirestore contains a Cloud Event Function triggered by a Cloud Firestore event.
package hellofirestore

import (
	"context"
	"fmt"

	"github.com/GoogleCloudPlatform/functions-framework-go/functions"
	"github.com/cloudevents/sdk-go/v2/event"
	"github.com/googleapis/google-cloudevents-go/cloud/firestoredata"
	"google.golang.org/protobuf/proto"
)

func init() {
	functions.CloudEvent("helloFirestore", HelloFirestore)
}

// HelloFirestore is triggered by a change to a Firestore document.
func HelloFirestore(ctx context.Context, event event.Event) error {
	var data firestoredata.DocumentEventData
	if err := proto.Unmarshal(event.Data(), &data); err != nil {
		return fmt.Errorf("proto.Unmarshal: %w", err)
	}

	fmt.Printf("Function triggered by change to: %v\n", event.Source())
	fmt.Printf("Old value: %+v\n", data.GetOldValue())
	fmt.Printf("New value: %+v\n", data.GetValue())
	return nil
}

Java

Per eseguire l'autenticazione su Firestore, configura le credenziali predefinite dell'applicazione. Per ulteriori informazioni, vedi Configura l'autenticazione per un ambiente di sviluppo locale.

import com.google.cloud.functions.CloudEventsFunction;
import com.google.events.cloud.firestore.v1.DocumentEventData;
import com.google.protobuf.InvalidProtocolBufferException;
import io.cloudevents.CloudEvent;
import java.util.logging.Logger;

public class FirebaseFirestore implements CloudEventsFunction {
  private static final Logger logger = Logger.getLogger(FirebaseFirestore.class.getName());

  @Override
  public void accept(CloudEvent event) throws InvalidProtocolBufferException {
    DocumentEventData firestorEventData = DocumentEventData.parseFrom(event.getData().toBytes());

    logger.info("Function triggered by event on: " + event.getSource());
    logger.info("Event type: " + event.getType());

    logger.info("Old value:");
    logger.info(firestorEventData.getOldValue().toString());

    logger.info("New value:");
    logger.info(firestorEventData.getValue().toString());
  }
}

Node.js

Per eseguire l'autenticazione su Firestore, configura le credenziali predefinite dell'applicazione. Per ulteriori informazioni, vedi Configura l'autenticazione per un ambiente di sviluppo locale.

Utilizza protobufjs per decodificare i dati sugli eventi. Includi l'elemento google.events.cloud.firestore.v1 data.proto nella fonte.
/**
 * Cloud Event Function triggered by a change to a Firestore document.
 */
const functions = require('@google-cloud/functions-framework');
const protobuf = require('protobufjs');

functions.cloudEvent('helloFirestore', async cloudEvent => {
  console.log(`Function triggered by event on: ${cloudEvent.source}`);
  console.log(`Event type: ${cloudEvent.type}`);

  console.log('Loading protos...');
  const root = await protobuf.load('data.proto');
  const DocumentEventData = root.lookupType(
    'google.events.cloud.firestore.v1.DocumentEventData'
  );

  console.log('Decoding data...');
  const firestoreReceived = DocumentEventData.decode(cloudEvent.data);

  console.log('\nOld value:');
  console.log(JSON.stringify(firestoreReceived.oldValue, null, 2));

  console.log('\nNew value:');
  console.log(JSON.stringify(firestoreReceived.value, null, 2));
});

Python

Per eseguire l'autenticazione su Firestore, configura le credenziali predefinite dell'applicazione. Per ulteriori informazioni, vedi Configura l'autenticazione per un ambiente di sviluppo locale.

from cloudevents.http import CloudEvent
import functions_framework
from google.events.cloud import firestore


@functions_framework.cloud_event
def hello_firestore(cloud_event: CloudEvent) -> None:
    """Triggers by a change to a Firestore document.

    Args:
        cloud_event: cloud event with information on the firestore event trigger
    """
    firestore_payload = firestore.DocumentEventData()
    firestore_payload._pb.ParseFromString(cloud_event.data)

    print(f"Function triggered by change to: {cloud_event['source']}")

    print("\nOld value:")
    print(firestore_payload.old_value)

    print("\nNew value:")
    print(firestore_payload.value)

C#

Per eseguire l'autenticazione su Firestore, configura le credenziali predefinite dell'applicazione. Per ulteriori informazioni, vedi Configura l'autenticazione per un ambiente di sviluppo locale.

using CloudNative.CloudEvents;
using Google.Cloud.Functions.Framework;
using Google.Events.Protobuf.Cloud.Firestore.V1;
using Microsoft.Extensions.Logging;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace FirebaseFirestore;

public class Function : ICloudEventFunction<DocumentEventData>
{
    private readonly ILogger _logger;

    public Function(ILogger<Function> logger) =>
        _logger = logger;

    public Task HandleAsync(CloudEvent cloudEvent, DocumentEventData data, CancellationToken cancellationToken)
    {
        _logger.LogInformation("Function triggered by event on {subject}", cloudEvent.Subject);
        _logger.LogInformation("Event type: {type}", cloudEvent.Type);
        MaybeLogDocument("Old value", data.OldValue);
        MaybeLogDocument("New value", data.Value);

        // In this example, we don't need to perform any asynchronous operations, so the
        // method doesn't need to be declared async.
        return Task.CompletedTask;
    }

    /// <summary>
    /// Logs the names and values of the fields in a document in a very simplistic way.
    /// </summary>
    private void MaybeLogDocument(string message, Document document)
    {
        if (document is null)
        {
            return;
        }

        // ConvertFields converts the Firestore representation into a .NET-friendly
        // representation.
        IReadOnlyDictionary<string, object> fields = document.ConvertFields();
        var fieldNamesAndTypes = fields
            .OrderBy(pair => pair.Key)
            .Select(pair => $"{pair.Key}: {pair.Value}");
        _logger.LogInformation(message + ": {fields}", string.Join(", ", fieldNamesAndTypes));
    }
}

Gli esempi seguenti convertono le stringhe aggiunte al campo original di un documento interessato in maiuscolo e scrive il nuovo valore nello stesso documento:

Go

Per eseguire l'autenticazione su Firestore, configura le credenziali predefinite dell'applicazione. Per ulteriori informazioni, vedi Configura l'autenticazione per un ambiente di sviluppo locale.


// Package upper contains a Firestore Cloud Function.
package upper

import (
	"context"
	"errors"
	"fmt"
	"log"
	"os"
	"strings"

	"cloud.google.com/go/firestore"
	firebase "firebase.google.com/go/v4"
	"github.com/GoogleCloudPlatform/functions-framework-go/functions"
	"github.com/cloudevents/sdk-go/v2/event"
	"github.com/googleapis/google-cloudevents-go/cloud/firestoredata"
	"google.golang.org/protobuf/proto"
)

// set the GOOGLE_CLOUD_PROJECT environment variable when deploying.
var projectID = os.Getenv("GOOGLE_CLOUD_PROJECT")

// client is a Firestore client, reused between function invocations.
var client *firestore.Client

func init() {
	// Use the application default credentials.
	conf := &firebase.Config{ProjectID: projectID}

	// Use context.Background() because the app/client should persist across
	// invocations.
	ctx := context.Background()

	app, err := firebase.NewApp(ctx, conf)
	if err != nil {
		log.Fatalf("firebase.NewApp: %v", err)
	}

	client, err = app.Firestore(ctx)
	if err != nil {
		log.Fatalf("app.Firestore: %v", err)
	}

	// Register cloud event function
	functions.CloudEvent("MakeUpperCase", MakeUpperCase)
}

// MakeUpperCase is triggered by a change to a Firestore document. It updates
// the `original` value of the document to upper case.
func MakeUpperCase(ctx context.Context, e event.Event) error {
	var data firestoredata.DocumentEventData
	if err := proto.Unmarshal(e.Data(), &data); err != nil {
		return fmt.Errorf("proto.Unmarshal: %w", err)
	}

	if data.GetValue() == nil {
		return errors.New("Invalid message: 'Value' not present")
	}

	fullPath := strings.Split(data.GetValue().GetName(), "/documents/")[1]
	pathParts := strings.Split(fullPath, "/")
	collection := pathParts[0]
	doc := strings.Join(pathParts[1:], "/")

	var originalStringValue string
	if v, ok := data.GetValue().GetFields()["original"]; ok {
		originalStringValue = v.GetStringValue()
	} else {
		return errors.New("Document did not contain field \"original\"")
	}

	newValue := strings.ToUpper(originalStringValue)
	if originalStringValue == newValue {
		log.Printf("%q is already upper case: skipping", originalStringValue)
		return nil
	}
	log.Printf("Replacing value: %q -> %q", originalStringValue, newValue)

	newDocumentEntry := map[string]string{"original": newValue}
	_, err := client.Collection(collection).Doc(doc).Set(ctx, newDocumentEntry)
	if err != nil {
		return fmt.Errorf("Set: %w", err)
	}
	return nil
}

Java

Per eseguire l'autenticazione su Firestore, configura le credenziali predefinite dell'applicazione. Per ulteriori informazioni, vedi Configura l'autenticazione per un ambiente di sviluppo locale.

import com.google.cloud.firestore.Firestore;
import com.google.cloud.firestore.FirestoreOptions;
import com.google.cloud.firestore.SetOptions;
import com.google.cloud.functions.CloudEventsFunction;
import com.google.events.cloud.firestore.v1.DocumentEventData;
import com.google.events.cloud.firestore.v1.Value;
import com.google.protobuf.InvalidProtocolBufferException;
import io.cloudevents.CloudEvent;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.logging.Logger;

public class FirebaseFirestoreReactive implements CloudEventsFunction {
  private static final Logger logger = Logger.getLogger(FirebaseFirestoreReactive.class.getName());
  private final Firestore firestore;

  private static final String FIELD_KEY = "original";
  private static final String APPLICATION_PROTOBUF = "application/protobuf";

  public FirebaseFirestoreReactive() {
    this(FirestoreOptions.getDefaultInstance().getService());
  }

  public FirebaseFirestoreReactive(Firestore firestore) {
    this.firestore = firestore;
  }

  @Override
  public void accept(CloudEvent event)
      throws InvalidProtocolBufferException, InterruptedException, ExecutionException {
    if (event.getData() == null) {
      logger.warning("No data found in event!");
      return;
    }

    if (!event.getDataContentType().equals(APPLICATION_PROTOBUF)) {
      logger.warning(String.format("Found unexpected content type %s, expected %s",
          event.getDataContentType(),
          APPLICATION_PROTOBUF));
      return;
    }

    DocumentEventData firestoreEventData = DocumentEventData
        .parseFrom(event.getData().toBytes());

    // Get the fields from the post-operation document snapshot
    // https://firebase.google.com/docs/firestore/reference/rest/v1/projects.databases.documents#Document
    Map<String, Value> fields = firestoreEventData.getValue().getFieldsMap();
    if (!fields.containsKey(FIELD_KEY)) {
      logger.warning("Document does not contain original field");
      return;
    }
    String currValue = fields.get(FIELD_KEY).getStringValue();
    String newValue = currValue.toUpperCase();

    if (currValue.equals(newValue)) {
      logger.info("Value is already upper-case");
      return;
    }

    // Retrieve the document name from the resource path:
    // projects/{project_id}/databases/{database_id}/documents/{document_path}
    String affectedDoc = firestoreEventData.getValue()
        .getName()
        .split("/documents/")[1]
        .replace("\"", "");

    logger.info(String.format("Replacing values: %s --> %s", currValue, newValue));

    // Wait for the async call to complete
    this.firestore
        .document(affectedDoc)
        .set(Map.of(FIELD_KEY, newValue), SetOptions.merge())
        .get();
  }
}

Node.js

Per eseguire l'autenticazione su Firestore, configura le credenziali predefinite dell'applicazione. Per ulteriori informazioni, vedi Configura l'autenticazione per un ambiente di sviluppo locale.

Utilizza protobufjs per decodificare i dati sugli eventi. Includi l'elemento google.events.cloud.firestore.v1 data.proto nella fonte.
const functions = require('@google-cloud/functions-framework');
const Firestore = require('@google-cloud/firestore');
const protobuf = require('protobufjs');

const firestore = new Firestore({
  projectId: process.env.GOOGLE_CLOUD_PROJECT,
});

// Converts strings added to /messages/{pushId}/original to uppercase
functions.cloudEvent('makeUpperCase', async cloudEvent => {
  console.log('Loading protos...');
  const root = await protobuf.load('data.proto');
  const DocumentEventData = root.lookupType(
    'google.events.cloud.firestore.v1.DocumentEventData'
  );

  console.log('Decoding data...');
  const firestoreReceived = DocumentEventData.decode(cloudEvent.data);

  const resource = firestoreReceived.value.name;
  const affectedDoc = firestore.doc(resource.split('/documents/')[1]);

  const curValue = firestoreReceived.value.fields.original.stringValue;
  const newValue = curValue.toUpperCase();

  if (curValue === newValue) {
    // Value is already upper-case
    // Don't perform a(nother) write to avoid infinite loops
    console.log('Value is already upper-case.');
    return;
  }

  console.log(`Replacing value: ${curValue} --> ${newValue}`);
  affectedDoc.set({
    original: newValue,
  });
});

Python

Per autenticarti a Firestore, configura le credenziali predefinite dell'applicazione. Per ulteriori informazioni, vedi Configura l'autenticazione per un ambiente di sviluppo locale.

from cloudevents.http import CloudEvent
import functions_framework
from google.cloud import firestore
from google.events.cloud import firestore as firestoredata

client = firestore.Client()


# Converts strings added to /messages/{pushId}/original to uppercase
@functions_framework.cloud_event
def make_upper_case(cloud_event: CloudEvent) -> None:
    firestore_payload = firestoredata.DocumentEventData()
    firestore_payload._pb.ParseFromString(cloud_event.data)

    path_parts = firestore_payload.value.name.split("/")
    separator_idx = path_parts.index("documents")
    collection_path = path_parts[separator_idx + 1]
    document_path = "/".join(path_parts[(separator_idx + 2) :])

    print(f"Collection path: {collection_path}")
    print(f"Document path: {document_path}")

    affected_doc = client.collection(collection_path).document(document_path)

    cur_value = firestore_payload.value.fields["original"].string_value
    new_value = cur_value.upper()

    if cur_value != new_value:
        print(f"Replacing value: {cur_value} --> {new_value}")
        affected_doc.set({"original": new_value})
    else:
        # Value is already upper-case
        # Don't perform a second write (which can trigger an infinite loop)
        print("Value is already upper-case.")

C#

Per eseguire l'autenticazione su Firestore, configura le credenziali predefinite dell'applicazione. Per ulteriori informazioni, vedi Configura l'autenticazione per un ambiente di sviluppo locale.

using CloudNative.CloudEvents;
using Google.Cloud.Firestore;
using Google.Cloud.Functions.Framework;
using Google.Cloud.Functions.Hosting;
using Google.Events.Protobuf.Cloud.Firestore.V1;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace FirestoreReactive;

public class Startup : FunctionsStartup
{
    public override void ConfigureServices(WebHostBuilderContext context, IServiceCollection services) =>
        services.AddSingleton(FirestoreDb.Create());
}

// Register the startup class to provide the Firestore dependency.
[FunctionsStartup(typeof(Startup))]
public class Function : ICloudEventFunction<DocumentEventData>
{
    private readonly ILogger _logger;
    private readonly FirestoreDb _firestoreDb;

    public Function(ILogger<Function> logger, FirestoreDb firestoreDb) =>
        (_logger, _firestoreDb) = (logger, firestoreDb);

    public async Task HandleAsync(CloudEvent cloudEvent, DocumentEventData data, CancellationToken cancellationToken)
    {
        // Get the recently-written value. This expression will result in a null value
        // if any of the following is true:
        // - The event doesn't contain a "new" document
        // - The value doesn't contain a field called "original"
        // - The "original" field isn't a string
        string currentValue = data.Value?.ConvertFields().GetValueOrDefault("original") as string;
        if (currentValue is null)
        {
            _logger.LogWarning($"Event did not contain a suitable document");
            return;
        }

        string newValue = currentValue.ToUpperInvariant();
        if (newValue == currentValue)
        {
            _logger.LogInformation("Value is already upper-cased; no replacement necessary");
            return;
        }

        // The CloudEvent subject is "documents/x/y/...".
        // The Firestore SDK FirestoreDb.Document method expects a reference relative to
        // "documents" (so just the "x/y/..." part). This may be simplified over time.
        if (cloudEvent.Subject is null || !cloudEvent.Subject.StartsWith("documents/"))
        {
            _logger.LogWarning("CloudEvent subject is not a document reference.");
            return;
        }
        string documentPath = cloudEvent.Subject.Substring("documents/".Length);

        _logger.LogInformation("Replacing '{current}' with '{new}' in '{path}'", currentValue, newValue, documentPath);
        await _firestoreDb.Document(documentPath).UpdateAsync("original", newValue, cancellationToken: cancellationToken);
    }
}

Includi le dipendenze proto nell'origine

Devi includere Firestore data.proto nella directory di origine per la tua funzione. Questo file importa i seguenti dati che devi includere anche nella directory di origine:

Usa la stessa struttura di directory per le dipendenze. Ad esempio, posiziona struct.proto in google/protobuf.

Questi file sono necessari per decodificare i dati sugli eventi. Se l'origine della funzione non non include questi file, restituisce un errore durante l'esecuzione.

Attributi evento

Ogni evento include attributi dei dati che includono informazioni sull'evento, come l'ora in cui l'evento è stato attivato. Firestore aggiunge ulteriori dati sul database e sul documento coinvolti nell'evento. Puoi accedere a questi attributi nel seguente modo:

Java
logger.info("Function triggered by event on: " + event.getSource());
logger.info("Event type: " + event.getType());
logger.info("Event time " + event.getTime());
logger.info("Event project: " + event.getExtension("project"));
logger.info("Event location: " + event.getExtension("location"));
logger.info("Database name: " + event.getExtension("database"));
logger.info("Database document: " + event.getExtension("document"));
// For withAuthContext events
logger.info("Auth information: " + event.getExtension("authid"));
logger.info("Auth information: " + event.getExtension("authtype"));
Node.js
console.log(`Function triggered by event on: ${cloudEvent.source}`);
console.log(`Event type: ${cloudEvent.type}`);
console.log(`Event time: ${cloudEvent.time}`);
console.log(`Event project: ${cloudEvent.project}`);
console.log(`Event location: ${cloudEvent.location}`);
console.log(`Database name: ${cloudEvent.database}`);
console.log(`Document name: ${cloudEvent.document}`);
// For withAuthContext events
console.log(`Auth information: ${cloudEvent.authid}`);
console.log(`Auth information: ${cloudEvent.authtype}`);
Python
print(f"Function triggered by change to: {cloud_event['source']}")
print(f"Event type: {cloud_event['type']}")
print(f"Event time: {cloud_event['time']}")
print(f"Event project: {cloud_event['project']}")
print(f"Location: {cloud_event['location']}")
print(f"Database name: {cloud_event['database']}")
print(f"Document: {cloud_event['document']}")
// For withAuthContext events
print(f"Auth information: {cloud_event['authid']}")
print(f"Auth information: {cloud_event['authtype']}")

Esegui il deployment di una funzione

Gli utenti che eseguono il deployment delle funzioni Cloud Run devono avere Sviluppatore funzioni Cloud Run un ruolo IAM o un ruolo che include le stesse autorizzazioni. Vedi anche Configurazione aggiuntiva per il deployment.

Puoi eseguire il deployment di una funzione utilizzando la riga di comando gcloud o la console Google Cloud. L'esempio seguente mostra il deployment con con gcloud CLI. Per maggiori dettagli sul deployment con la console Google Cloud, consulta Eseguire il deployment delle funzioni di Cloud Run

gcloud

  1. In the Google Cloud console, activate Cloud Shell.

    Activate Cloud Shell

    At the bottom of the Google Cloud console, a Cloud Shell session starts and displays a command-line prompt. Cloud Shell is a shell environment with the Google Cloud CLI already installed and with values already set for your current project. It can take a few seconds for the session to initialize.

  2. Utilizza la gcloud functions deploy per eseguire il deployment di una funzione:

    gcloud functions deploy YOUR_FUNCTION_NAME \
    --gen2 \
    --region=FUNCTION_LOCATION \
    --trigger-location=TRIGGER_LOCATION \
    --runtime=YOUR_RUNTIME \
    --source=YOUR_SOURCE_LOCATION \
    --entry-point=YOUR_CODE_ENTRYPOINT \
    --trigger-event-filters="type=EVENT_FILTER_TYPE" \
    --trigger-event-filters="database=DATABASE" \
    --trigger-event-filters-path-pattern="document=DOCUMENT" \
    

    Il primo argomento, YOUR_FUNCTION_NAME, è un nome per della funzione di cui hai eseguito il deployment. Il nome della funzione deve iniziare con una lettera seguito da un massimo di 62 lettere, numeri, trattini o trattini bassi e deve terminare con una lettera o un numero.

    • Il flag --gen2 specifica che vuoi eseguire il deployment su funzioni Cloud Run (2ª generazione). Omissione questo flag porta al deployment in Cloud Run Functions (1ª generazione.).

    • Il flag --region specifica la regione in cui eseguire il deployment della funzione.

      Per massimizzare la prossimità, imposta una regione vicina a Firestore per configurare un database. Se il database Firestore si trova in una località multiregionale località, impostata su us-central1 per i database in nam5 e su europe-west4 per i database in eur3. Per regioni Località Firestore, impostate sulla stessa regione.

    • La --trigger-location specifica la posizione del trigger. Devi impostare questo flag su del tuo database Firestore.

    • Il flag --runtime specifica il runtime del linguaggio utilizzato dalla funzione. Funzioni di Cloud Run supporta diversi runtime, vedi Runtime per ulteriori informazioni.

    • Il flag --source specifica la posizione del codice sorgente della funzione. Consulta quanto segue: per maggiori dettagli:

    • La --entry-point specifica il punto di ingresso della funzione nel codice sorgente. Questo è il codice che verrà eseguito quando la funzione viene eseguita. Il valore di questo deve essere un nome di funzione o un nome di classe completo esistente del codice sorgente. Consulta Punto di ingresso alla funzione per ulteriori informazioni.

    • EVENT_FILTER_TYPE: Firestore supporta i seguenti tipi di eventi.

      • google.cloud.firestore.document.v1.created: l'evento viene inviato quando del documento per la prima volta.
      • google.cloud.firestore.document.v1.updated: l'evento viene inviato quando documento già esistente e con qualsiasi valore modificato.
      • google.cloud.firestore.document.v1.deleted: l'evento viene inviato quando documento eliminato.
      • google.cloud.firestore.document.v1.written: l'evento viene inviato quando quando un documento viene creato, aggiornato o eliminato.
      • google.cloud.firestore.document.v1.created.withAuthContext: l'evento viene inviato quando documento è scritto per la prima volta e l'evento include ulteriori informazioni di autenticazione.
      • google.cloud.firestore.document.v1.updated.withAuthContext: l'evento viene inviato quando documento già esistente e con qualsiasi valore modificato. Include informazioni di autenticazione aggiuntive
      • google.cloud.firestore.document.v1.deleted.withAuthContext: l'evento viene inviato quando documento eliminato. Include informazioni di autenticazione aggiuntive
      • google.cloud.firestore.document.v1.written.withAuthContext: l'evento viene inviato quando viene creato, aggiornato o eliminato ed evento. Include informazioni di autenticazione aggiuntive
    • DATABASE: il database Firestore. Per il nome predefinito del database, utilizza (default).

    • DOCUMENT: il percorso del database attiva eventi quando i dati vengono creati, aggiornati eliminati. L'operatore può essere uno dei seguenti:

      • Uguale; ad esempio --trigger-event-filters=document='users/marie'
      • Pattern del percorso; ad esempio --trigger-event-filters-path-pattern=document='users/*'. Per saperne di più, consulta Comprendere i pattern dei percorsi.

    Facoltativamente, puoi specificare ulteriori configurazione, networking e le opzioni di sicurezza quando esegui il deployment di una funzione.

    Per un riferimento completo al comando di deployment e ai relativi flag, consulta la documentazione di gcloud functions deploy.

Deployment di esempio

I seguenti esempi dimostrano i deployment con Google Cloud CLI.

Esegui il deployment di una funzione per un database nella regione us-west2:

gcloud functions deploy gcfv2-trigger-firestore-node \
--gen2 \
--region=us-west2 \
--trigger-location=us-west2 \
--runtime=nodejs18 \
--source=gs://CLOUD_STORAGE_BUCKET/firestoreEventFunction.zip \
--entry-point=makeUpperCase \
--trigger-event-filters=type=google.cloud.firestore.document.v1.written \
--trigger-event-filters=database='(default)' \
--trigger-event-filters-path-pattern=document='messages/{pushId}'

Esegui il deployment di una funzione per un database nella località multiregionale nam5:

gcloud functions deploy gcfv2-trigger-firestore-python \
--gen2 \
--region=us-central1 \
--trigger-location=nam5 \
--runtime=python311 \
--source=gs://CLOUD_STORAGE_BUCKET/firestoreEventFunction.zip \
--entry-point=make_upper_case \
--trigger-event-filters=type=google.cloud.firestore.document.v1.written.withAuthContext \
--trigger-event-filters=database='(default)' \
--trigger-event-filters-path-pattern=document='messages/{pushId}'

Limitazioni

Tieni presente le seguenti limitazioni per i trigger di Firestore per le funzioni di Cloud Run:

  • Le funzioni Cloud Run (1ª generazione.) preparano un prerequisito "(predefinito)" esistente in modalità nativa Firestore. Non supportare i database denominati Firestore o la modalità Datastore. Utilizza le funzioni di Cloud Run (2ª generazione) per configurare gli eventi in questi casi.
  • L'ordine non è garantito. Modifiche rapide possono attivare chiamate di funzione in un ordine inaspettato.
  • Gli eventi vengono pubblicati almeno una volta, ma un singolo evento può comportare più chiamate di funzione. Evita di fare affidamento su meccanismi di esecuzione esattamente una volta e scrivi funzioni idempotenti.
  • Firestore in modalità Datastore richiede le funzioni Cloud Run (2ª generazione.). Le funzioni Cloud Run (1ª gen.) non supportano la modalità Datastore.
  • Un trigger è associato a un singolo database. Non puoi creare un trigger che corrisponde a più database.
  • L'eliminazione di un database non elimina automaticamente alcun trigger per quel database. L'attivatore interrompe l'invio di eventi, ma continua a esistere finché non lo elimini.
  • Se un evento corrispondente supera le dimensioni massime della richiesta, il valore potrebbe non essere consegnato a Cloud Run Functions (1ª generazione.).
    • Gli eventi non consegnati a causa delle dimensioni della richiesta vengono registrati nei log della piattaforma e verranno conteggiate ai fini dell'utilizzo dei log da parte del progetto.
    • Puoi trovare questi log in Esplora log con il messaggio "L'evento non può recapitare a Funzione Cloud Functions a causa del superamento del limite per le dimensioni di 1ª generazione..." di error gravità. Puoi trovare il nome della funzione sotto il campo functionName. Se Se il campo receiveTimestamp si trova ancora a meno di un'ora da adesso, puoi dedurre i contenuti dell'evento effettivo leggendo il documento in questione con una uno snapshot prima e dopo il timestamp.
    • Per evitare questa frequenza, puoi:
      • Esegui la migrazione e l'upgrade a Cloud Run Functions (2ª generazione.)
      • Riduci le dimensioni del documento
      • Elimina le funzioni Cloud Run in questione
    • Puoi disattivare il logging utilizzando le esclusioni ma tieni presente che gli eventi offensivi non verranno comunque pubblicati.

Località Eventarc e Firestore

Eventarc non supporta più regioni per l'evento Firestore ma puoi comunque creare trigger per i database Firestore in località multiregionali. Eventarc mappa Firestore località multiregionali alle seguenti regioni Eventarc:

Firestore (più regioni) Regione Eventarc
nam5 us-central1
eur3 europe-west4

Differenze tra le funzioni Cloud Run (2ª generazione. e 1ª generazione.)

Le funzioni Cloud Run (2ª generazione) utilizzano gli eventi Eventarc per tutti i runtime. In precedenza, le funzioni Cloud Run (1ª generazione.) utilizzavano gli eventi Eventarc per solo alcuni runtime. Gli eventi Eventarc presentano le seguenti differenze rispetto alle funzioni Cloud Run (1ª gen.).

  • I trigger Firestore per il supporto Eventarc oltre alle funzioni di Cloud Run. Puoi indirizzare CloudEvents verso una serie di destinazioni, tra cui a titolo esemplificativo, Cloud Run, GKE Workflows.

  • I trigger di Firestore per Eventarc recuperano la definizione del trigger all'inizio di un'operazione di scrittura del database e utilizza quella definizione per decidere se Firestore deve emettere un evento. La l'operazione di scrittura non prende in considerazione le modifiche apportate all'attivatore della definizione che potrebbe verificarsi durante l'esecuzione.

    Le funzioni Cloud Run (1ª gen.) recuperano la definizione dell'attivatore durante la valutazione della scrittura del database e le modifiche all'attivatore durante la valutazione possono influire sull'emissione o meno di un evento da parte di Firestore.

Per maggiori dettagli, consulta Confronto delle versioni di Cloud Run Functions.