Trigger di Google Cloud Firestore (1ª generazione.)

Le funzioni Cloud Run possono gestire gli eventi in Firestore nello stesso progetto Google Cloud della funzione. Puoi leggere o aggiornare Firestore in risposta a questi eventi utilizzando le API e le librerie client di Firestore.

In un ciclo di vita tipico, una funzione Firestore esegue le seguenti operazioni:

  1. Attende le modifiche a un determinato documento.

  2. Si attiva quando si verifica un evento ed esegue le relative attività.

  3. Riceve un oggetto dati con uno snapshot del documento interessato. Per gli eventi write o update, l'oggetto dati contiene istantanee che rappresentano lo stato del documento prima e dopo l'evento di attivazione.

Tipi di evento

Firestore supporta gli eventi create, update, delete e write. L'evento write include tutte le modifiche a un documento.

Tipo di evento Trigger
providers/cloud.firestore/eventTypes/document.create (valore predefinito) Si attiva quando viene scritto per la prima volta in un documento.
providers/cloud.firestore/eventTypes/document.update Viene attivato quando esiste già un documento e un valore è stato modificato.
providers/cloud.firestore/eventTypes/document.delete Viene attivato quando viene eliminato un documento con dati.
providers/cloud.firestore/eventTypes/document.write Viene attivato quando un documento viene creato, aggiornato o eliminato.

I caratteri jolly vengono scritti negli attivatori utilizzando le parentesi graffe, come segue: "projects/YOUR_PROJECT_ID/databases/(default)/documents/collection/{document_wildcard}"

Specifica il percorso del documento

Per attivare la funzione, specifica un percorso del documento da monitorare. Le funzioni rispondono solo alle modifiche del documento e non possono monitorare campi o collezioni specifici. Di seguito sono riportati alcuni esempi di percorsi dei documenti validi:

  • users/marie: trigger valido. Monitora un singolo documento, /users/marie.

  • users/{username}: trigger valido. Monitora tutti i documenti dell'utente. I caratteri jolly vengono utilizzati per monitorare tutti i documenti della raccolta.

  • users/{username}/addresses: attivatore non valido. Si riferisce alla sottoraccoltaaddresses, non a un documento.

  • users/{username}/addresses/home: trigger valido. Monitora il documento dell'indirizzo di casa per tutti gli utenti.

  • users/{username}/addresses/{addressId}: trigger valido. Monitora tutti i documenti relativi all'indirizzo.

Utilizzo di caratteri jolly e parametri

Se non conosci il documento specifico che vuoi monitorare, utilizza un {wildcard} instead of the document ID:

  • users/{username} rileva le modifiche a tutti i documenti dell'utente.

In questo esempio, quando un campo di qualsiasi documento in users viene modificato, corrisponde a un carattere jolly chiamato {username}.

Se un documento in users ha sottocollezioni e un campo in uno dei documenti di queste sottocollezioni viene modificato, il carattere jolly {username} non viene attivato.

Le corrispondenze con caratteri jolly vengono estratte dai percorsi dei documenti. Puoi definire tutti i caratteri jolly che vuoi per sostituire ID raccolta o documento espliciti.

Struttura dell'evento

Questo attivatore invoca la funzione con un evento simile a quello mostrato di seguito:

{
    "oldValue": { // Update and Delete operations only
        A Document object containing a pre-operation document snapshot
    },
    "updateMask": { // Update operations only
        A DocumentMask object that lists changed fields.
    },
    "value": {
        // A Document object containing a post-operation document snapshot
    }
}

Ogni oggetto Document contiene uno o più oggetti Value. Per i riferimenti ai tipi, consulta la documentazione di Value. Questa operazione è particolarmente utile se utilizzi un linguaggio a tipi (come Go) per scrivere le funzioni.

Esempio di codice

La Cloud Function di esempio riportata di seguito stampa i campi di un evento Cloud Firestore di attivazione:

Node.js

/**
 * Background Function triggered by a change to a Firestore document.
 *
 * @param {!Object} event The Cloud Functions event.
 * @param {!Object} context Cloud Functions event metadata.
 */
exports.helloFirestore = (event, context) => {
  const triggerResource = context.resource;

  console.log(`Function triggered by event on: ${triggerResource}`);
  console.log(`Event type: ${context.eventType}`);

  if (event.oldValue && Object.keys(event.oldValue).length) {
    console.log('\nOld value:');
    console.log(JSON.stringify(event.oldValue, null, 2));
  }

  if (event.value && Object.keys(event.value).length) {
    console.log('\nNew value:');
    console.log(JSON.stringify(event.value, null, 2));
  }
};

Python

import json

def hello_firestore(data, context):
    """Triggered by a change to a Firestore document.
    Args:
        data (dict): The event payload.
        context (google.cloud.functions.Context): Metadata for the event.
    """
    trigger_resource = context.resource

    print("Function triggered by change to: %s" % trigger_resource)

    print("\nOld value:")
    print(json.dumps(data["oldValue"]))

    print("\nNew value:")
    print(json.dumps(data["value"]))

Vai


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

import (
	"context"
	"fmt"
	"log"
	"time"

	"cloud.google.com/go/functions/metadata"
)

// FirestoreEvent is the payload of a Firestore event.
type FirestoreEvent struct {
	OldValue   FirestoreValue `json:"oldValue"`
	Value      FirestoreValue `json:"value"`
	UpdateMask struct {
		FieldPaths []string `json:"fieldPaths"`
	} `json:"updateMask"`
}

// FirestoreValue holds Firestore fields.
type FirestoreValue struct {
	CreateTime time.Time `json:"createTime"`
	// Fields is the data for this value. The type depends on the format of your
	// database. Log the interface{} value and inspect the result to see a JSON
	// representation of your database fields.
	Fields     interface{} `json:"fields"`
	Name       string      `json:"name"`
	UpdateTime time.Time   `json:"updateTime"`
}

// HelloFirestore is triggered by a change to a Firestore document.
func HelloFirestore(ctx context.Context, e FirestoreEvent) error {
	meta, err := metadata.FromContext(ctx)
	if err != nil {
		return fmt.Errorf("metadata.FromContext: %w", err)
	}
	log.Printf("Function triggered by change to: %v", meta.Resource)
	log.Printf("Old value: %+v", e.OldValue)
	log.Printf("New value: %+v", e.Value)
	return nil
}

Java

import com.google.cloud.functions.Context;
import com.google.cloud.functions.RawBackgroundFunction;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import java.util.logging.Logger;

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

  // Use GSON (https://github.com/google/gson) to parse JSON content.
  private static final Gson gson = new Gson();

  @Override
  public void accept(String json, Context context) {
    JsonObject body = gson.fromJson(json, JsonObject.class);
    logger.info("Function triggered by event on: " + context.resource());
    logger.info("Event type: " + context.eventType());

    if (body != null && body.has("oldValue")) {
      logger.info("Old value:");
      logger.info(body.get("oldValue").getAsString());
    }

    if (body != null && body.has("value")) {
      logger.info("New value:");
      logger.info(body.get("value").getAsString());
    }
  }
}

C#

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

Ruby

require "functions_framework"

# Triggered by a change to a Firestore document.
FunctionsFramework.cloud_event "hello_firestore" do |event|
  # The event parameter is a CloudEvents::Event::V1 object.
  # See https://cloudevents.github.io/sdk-ruby/latest/CloudEvents/Event/V1.html
  payload = event.data

  logger.info "Function triggered by change to: #{event.source}"
  logger.info "Old value: #{payload['oldValue']}"
  logger.info "New value: #{payload['value']}"
end

PHP


use Google\CloudFunctions\CloudEvent;

function firebaseFirestore(CloudEvent $cloudevent)
{
    $log = fopen(getenv('LOGGER_OUTPUT') ?: 'php://stderr', 'wb');

    fwrite($log, 'Event: ' . $cloudevent->getId() . PHP_EOL);
    fwrite($log, 'Event Type: ' . $cloudevent->getType() . PHP_EOL);

    $data = $cloudevent->getData();

    $resource = $data['resource'];
    fwrite($log, 'Function triggered by event on: ' . $resource . PHP_EOL);

    if (isset($data['oldValue'])) {
        fwrite($log, 'Old value: ' . json_encode($data['oldValue']) . PHP_EOL);
    }

    if (isset($data['value'])) {
        fwrite($log, 'New value: ' . json_encode($data['value']) . PHP_EOL);
    }
}

L'esempio seguente recupera il valore aggiunto dall'utente, converte la stringa in quella posizione in maiuscolo e sostituisce il valore con la stringa in maiuscolo:

Node.js

const Firestore = require('@google-cloud/firestore');

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

// Converts strings added to /messages/{pushId}/original to uppercase
exports.makeUpperCase = event => {
  const resource = event.value.name;
  const affectedDoc = firestore.doc(resource.split('/documents/')[1]);

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

  if (curValue !== newValue) {
    console.log(`Replacing value: ${curValue} --> ${newValue}`);

    return affectedDoc.set({
      original: newValue,
    });
  } else {
    // Value is already upper-case
    // Don't perform a(nother) write to avoid infinite loops
    console.log('Value is already upper-case.');
  }
};

Python

from google.cloud import firestore

client = firestore.Client()


# Converts strings added to /messages/{pushId}/original to uppercase
def make_upper_case(data, context):
    path_parts = context.resource.split("/documents/")[1].split("/")
    collection_path = path_parts[0]
    document_path = "/".join(path_parts[1:])

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

    cur_value = data["value"]["fields"]["original"]["stringValue"]
    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.")

Vai


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

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

	"cloud.google.com/go/firestore"
	firebase "firebase.google.com/go/v4"
)

// FirestoreEvent is the payload of a Firestore event.
type FirestoreEvent struct {
	OldValue   FirestoreValue `json:"oldValue"`
	Value      FirestoreValue `json:"value"`
	UpdateMask struct {
		FieldPaths []string `json:"fieldPaths"`
	} `json:"updateMask"`
}

// FirestoreValue holds Firestore fields.
type FirestoreValue struct {
	CreateTime time.Time `json:"createTime"`
	// Fields is the data for this value. The type depends on the format of your
	// database. Log an interface{} value and inspect the result to see a JSON
	// representation of your database fields.
	Fields     MyData    `json:"fields"`
	Name       string    `json:"name"`
	UpdateTime time.Time `json:"updateTime"`
}

// MyData represents a value from Firestore. The type definition depends on the
// format of your database.
type MyData struct {
	Original struct {
		StringValue string `json:"stringValue"`
	} `json:"original"`
}

// GOOGLE_CLOUD_PROJECT is automatically set by the Cloud Functions runtime.
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)
	}
}

// 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 FirestoreEvent) error {
	fullPath := strings.Split(e.Value.Name, "/documents/")[1]
	pathParts := strings.Split(fullPath, "/")
	collection := pathParts[0]
	doc := strings.Join(pathParts[1:], "/")

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

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

Java


import com.google.cloud.firestore.Firestore;
import com.google.cloud.firestore.FirestoreOptions;
import com.google.cloud.firestore.SetOptions;
import com.google.cloud.functions.Context;
import com.google.cloud.functions.RawBackgroundFunction;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class FirebaseFirestoreReactive implements RawBackgroundFunction {

  // Use GSON (https://github.com/google/gson) to parse JSON content.
  private static final Gson gson = new Gson();

  private static final Logger logger = Logger.getLogger(FirebaseFirestoreReactive.class.getName());
  private static final Firestore FIRESTORE = FirestoreOptions.getDefaultInstance().getService();

  private final Firestore firestore;

  public FirebaseFirestoreReactive() {
    this(FIRESTORE);
  }

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

  @Override
  public void accept(String json, Context context) {
    // Get the recently-written value
    JsonObject body = gson.fromJson(json, JsonObject.class);
    JsonObject tempJson = body.getAsJsonObject("value");

    // Verify that value.fields.original.stringValue exists
    String currentValue = null;
    if (tempJson != null) {
      tempJson = tempJson.getAsJsonObject("fields");
    }
    if (tempJson != null) {
      tempJson = tempJson.getAsJsonObject("original");
    }
    if (tempJson != null && tempJson.has("stringValue")) {
      currentValue = tempJson.get("stringValue").getAsString();
    }
    if (currentValue == null) {
      throw new IllegalArgumentException("Malformed JSON: " + json);
    }

    // Convert recently-written value to ALL CAPS
    String newValue = currentValue.toUpperCase(Locale.getDefault());

    // Update Firestore DB with ALL CAPS value
    Map<String, String> newFields = Map.of("original", newValue);

    String affectedDoc = context.resource().split("/documents/")[1].replace("\"", "");

    if (!currentValue.equals(newValue)) {
      // The stored value needs to be updated
      // Write the upper-cased value to Firestore
      logger.info(String.format("Replacing value: %s --> %s", currentValue, newValue));
      try {
        FIRESTORE.document(affectedDoc).set(newFields, SetOptions.merge()).get();
      } catch (ExecutionException | InterruptedException e) {
        logger.log(Level.SEVERE, "Error updating Firestore document: " + e.getMessage(), e);
      }
    } else {
      // The stored value is already upper-case, and doesn't need updating.
      // (Don't perform a "second" write, since that could trigger an infinite loop.)
      logger.info(String.format("Value is already upper-case."));
    }
  }
}

C#

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

Ruby

require "functions_framework"

FunctionsFramework.on_startup do
  # Lazily construct a Firestore client when needed, and reuse it on
  # subsequent calls.
  set_global :firestore_client do
    require "google/cloud/firestore"
    Google::Cloud::Firestore.new project_id: ENV["GOOGLE_CLOUD_PROJECT"]
  end
end

# Converts strings added to /messages/{pushId}/original to uppercase
FunctionsFramework.cloud_event "make_upper_case" do |event|
  # Event-triggered Ruby functions receive a CloudEvents::Event::V1 object.
  # See https://cloudevents.github.io/sdk-ruby/latest/CloudEvents/Event/V1.html
  # The Firebase event payload can be obtained from the event data.
  cur_value = event.data["value"]["fields"]["original"]["stringValue"]

  # Compute new value and determine whether it needs to be modified.
  # If the value is already upper-case, don't perform another write,
  # to avoid infinite loops.
  new_value = cur_value.upcase
  if cur_value == new_value
    logger.info "Value is already upper-case"
    return
  end

  # Use the Firestore client library to update the value.
  # The document name can be obtained from the event subject.
  logger.info "Replacing value: #{cur_value} --> #{new_value}"
  doc_name = event.subject.split("documents/").last
  affected_doc = global(:firestore_client).doc doc_name
  new_doc_data = { original: new_value }
  affected_doc.set new_doc_data, merge: false
end

PHP


use Google\Cloud\Firestore\FirestoreClient;
use Google\CloudFunctions\CloudEvent;

function firebaseReactive(CloudEvent $cloudevent)
{
    $log = fopen(getenv('LOGGER_OUTPUT') ?: 'php://stderr', 'wb');
    $data = $cloudevent->getData();

    $resource = $data['value']['name'];

    $db = new FirestoreClient();

    $docPath = explode('/documents/', $resource)[1];

    $affectedDoc = $db->document($docPath);

    $curValue = $data['value']['fields']['original']['stringValue'];
    $newValue = strtoupper($curValue);

    if ($curValue !== $newValue) {
        fwrite($log, 'Replacing value: ' . $curValue . ' --> ' . $newValue . PHP_EOL);

        $affectedDoc->set(['original' => $newValue]);
    } else {
        // Value is already upper-case
        // Don't perform another write (it might cause an infinite loop)
        fwrite($log, 'Value is already upper-case.' . PHP_EOL);
    }
}

Eseguire il deployment della funzione

Il seguente comando gcloud esegue il deployment di una funzione attivata da eventi di scrittura sul documento /messages/{pushId}:

gcloud functions deploy FUNCTION_NAME \
  --no-gen2 \
  --entry-point ENTRY_POINT \
  --runtime RUNTIME \
  --set-env-vars GOOGLE_CLOUD_PROJECT=YOUR_PROJECT_ID \
  --trigger-event "providers/cloud.firestore/eventTypes/document.write" \
  --trigger-resource "projects/YOUR_PROJECT_ID/databases/(default)/documents/messages/{pushId}"
Argomento Descrizione
FUNCTION_NAME Il nome registrato della Cloud Function di cui stai eseguendo il deployment. Può essere il nome di una funzione nel codice sorgente o una stringa arbitraria. Se FUNCTION_NAME è una stringa arbitraria, devi includere il flag --entry-point.
--entry-point ENTRY_POINT Il nome di una funzione o di una classe nel codice sorgente. Facoltativo, a meno che non abbia utilizzato FUNCTION_NAME per specificare la funzione nel codice sorgente da eseguire durante il deployment. In questo caso, devi utilizzare --entry-point per fornire il nome della funzione eseguibile.
--runtime RUNTIME Il nome del runtime in uso. Per un elenco completo, consulta il riferimento gcloud.
--set-env-vars GOOGLE_CLOUD_PROJECT=YOUR_PROJECT_ID L'identificatore univoco del progetto come variabile di ambiente di runtime.
--trigger-event NAME Il tipo di evento che la funzione monitorerà (uno tra write, create, update o delete).
--trigger-resource NAME Il percorso completo del database a cui la funzione sarà in ascolto. Deve essere conforme al seguente formato: "projects/YOUR_PROJECT_ID/databases/(default)/documents/PATH" Il testo {pushId} è un parametro jolly descritto sopra in Specificare il percorso del documento.

Limitazioni

Tieni presenti le seguenti limitazioni per gli trigger Firestore per le funzioni Cloud Run:

  • Le funzioni Cloud Run (1ª generazione.) richiedono un database "(default)" esistente in modalità nativa Firestore. Non supporta i database Firestore con nome o la modalità Datastore. Utilizza le funzioni Cloud Run (2ª generazione.) per configurare gli eventi in questi casi.
  • L'ordine non è garantito. Le variazioni rapide possono attivare le chiamate di funzione in un ordine imprevisto.
  • Gli eventi vengono inviati 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 Cloud Run Functions (2ª generazione.). Le funzioni Cloud Run (1ª generazione.) non supportano la modalità Datastore.
  • Un trigger è associato a un singolo database. Non puoi creare un attivatore che corrisponda a più database.
  • L'eliminazione di un database non comporta l'eliminazione automatica degli attivatori per quel database. L'attivatore interrompe l'invio di eventi, ma continua a esistere finché non lo elimini.
  • Se un evento con corrispondenza supera la dimensione massima della richiesta, l'evento potrebbe non essere inviato alle funzioni Cloud Run (1ª generazione.).
    • Gli eventi non inviati a causa delle dimensioni della richiesta vengono registrati nei log della piattaforma e conteggiati ai fini dell'utilizzo dei log per il progetto.
    • Puoi trovare questi log in Esplora log con il messaggio "Impossibile inviare l'evento alla funzione Cloud perché le dimensioni superano il limite per la 1ª gen." di gravità error. Puoi trovare il nome della funzione nel campo functionName. Se il campo receiveTimestamp è ancora entro un'ora da adesso, puoi dedurre i contenuti effettivi dell'evento leggendo il documento in questione con uno snapshot prima e dopo il timestamp.
    • Per evitare questa cadenza, 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 stesso utilizzando le esclusioni, ma tieni presente che gli eventi in violazione non verranno comunque inviati.