Datastore mit Cloud Functions erweitern (2. Generation)

Mit Cloud Functions und Eventarc können Sie Code bereitstellen, um Ereignisse zu verarbeiten, die durch Änderungen in Ihrer Firestore-Datenbank im Datastore-Modus ausgelöst werden. So können Sie serverseitige Funktionen hinzufügen, ohne eigene Server betreiben zu müssen.

Trigger im Datastore-Modus

Eventarc unterstützt die folgenden Ereignistrigger in Firestore im Datastore-Modus, damit Sie Cloud Functions-Handler (2. Generation) erstellen können, die mit Firestore-Ereignissen im Datastore-Modus verknüpft sind:

Ereignistyp Trigger
google.cloud.datastore.entity.v1.created Wird ausgelöst, wenn eine Entität zum ersten Mal geschrieben wird.
google.cloud.datastore.entity.v1.updated Wird ausgelöst, wenn eine Entität bereits vorhanden ist und sich ein Wert geändert hat.
google.cloud.datastore.entity.v1.deleted Wird ausgelöst, wenn eine Entität gelöscht wird.
google.cloud.datastore.entity.v1.written Wird ausgelöst, wenn created, updated oder deleted ausgelöst wird.
google.cloud.datastore.entity.v1.created.withAuthContext Wie „created“, aber es werden Authentifizierungsinformationen hinzugefügt.
google.cloud.datastore.entity.v1.updated.withAuthContext Wie „updated“, aber es werden Authentifizierungsinformationen hinzugefügt.
google.cloud.datastore.entity.v1.deleted.withAuthContext Wie „deleted“, aber es werden Authentifizierungsinformationen hinzugefügt.
google.cloud.datastore.entity.v1.written.withAuthContext Wie „written“, aber es werden Authentifizierungsinformationen hinzugefügt.

Ereignistrigger im Datastore-Modus reagieren nur auf Entitätsänderungen. Bei einer Aktualisierung einer Entität im Datastore-Modus, bei der die Daten unverändert sind (ein No-Op-Schreiben), wird kein Aktualisierungs- oder Schreibereignis generiert. Ereignisse lassen sich nicht nur für bestimmte Properties generieren.

Authentifizierungskontext in das Ereignis aufnehmen

Wenn Sie dem Ereignis zusätzliche Authentifizierungsinformationen hinzufügen möchten, verwenden Sie einen Ereignistrigger mit der Erweiterung withAuthContext. Durch diese Erweiterung werden zusätzliche Informationen zum Hauptkonto hinzugefügt, das das Ereignis ausgelöst hat. Zusätzlich zu den im Basisereignis zurückgegebenen Informationen werden die Attribute authtype und authid hinzugefügt. Weitere Informationen zu Attributwerten finden Sie in der Referenz zu authcontext.

Durch Entität ausgelöste Funktion schreiben

Wenn Sie eine Funktion schreiben möchten, die auf Ereignisse in Firestore im Datastore-Modus reagiert, müssen Sie bei der Bereitstellung Folgendes angeben:

  • Triggerereignistyp
  • einen Triggerereignisfilter, um die mit der Funktion verknüpften Entitäten auszuwählen
  • Funktionscode für die Ausführung

Filter für Triggerereignisse

Wenn Sie einen Ereignisfilter angeben, können Sie entweder eine genaue Entitätsübereinstimmung oder ein Pfadmuster angeben. Verwenden Sie ein Pfadmuster, um mehrere Entitäten mit den Platzhaltern * oder ** abzugleichen.

Sie können beispielsweise eine genaue Entitätsübereinstimmung angeben, um auf Änderungen an der folgenden Entität zu reagieren:

users/marie

Verwenden Sie die Platzhalter * oder **, um auf Änderungen in Entitäten zu reagieren, die einem Muster entsprechen. Der Platzhalter * entspricht einem einzelnen Segment und der Platzhalter ** mit mehreren Segmenten entspricht null oder mehr Segmenten im Muster.

Für einzelne Segmentübereinstimmungen (*) können Sie auch eine benannte Erfassungsgruppe wie users/{userId} verwenden.

Die folgende Tabelle zeigt gültige Pfadmuster:

Muster Beschreibung
users/* oder users/{userId} Stimmt mit allen Entitäten der Art users überein. Stimmt nicht mit der Ebene von Nachfolgerentitäten wie /users/marie/messages/33e2IxYBD9enzS50SJ68 überein
users/** Gleicht alle Entitäten der Art users und alle untergeordneten Entitäten wie /users/marie/messages/33e2IxYBD9enzS50SJ68 ab

Weitere Informationen zu Pfadmustern finden Sie unter Eventarc-Pfadmuster.

Der Trigger muss immer auf eine Entität verweisen, auch wenn Sie einen Platzhalter verwenden. Betrachten Sie die folgenden Beispiele:

  • users/{userId=*}/{messages=*} ist ungültig, da {messages=*} eine Art-ID ist.

  • users/{userId=*}/{messages}/{messageId=*} ist gültig, da {messageId=*} immer auf eine Entität verweist.

Maskierung von Zeichen

In diesem Abschnitt werden Situationen beschrieben, in denen Zeichen in Typ-IDs und Entitäts-IDs mit Escapezeichen maskiert werden müssen. Wenn Sie ein Zeichen mit Escapezeichen versehen, kann die ID im Ereignisfilter richtig interpretiert werden.

  • Wenn eine Art-ID oder Entitäts-ID das Zeichen ~ oder / enthält, muss die ID in Ihrem Ereignisfilter maskiert werden. Verwenden Sie das Format __escENCODED_ID__, um eine ID mit Escapezeichen zu versehen. Ersetzen Sie ENCODED_ID durch eine Art-ID oder Entitäts-ID, in der alle Zeichen ~ und / durch ihre Codierungs-IDs ersetzt werden:

    • ~: ~0
    • /: ~1

    Die Typ-ID user/profile wird beispielsweise zu __escusers~1profile__. Ein Beispiel für ein Pfadmuster mit dieser Art-ID ist __escusers~1profile__/{userId}.

  • Wenn Sie die Art-ID oder Entitäts-ID von . oder .. in Ihrem Ereignisfilter verwenden, müssen Sie die ID so maskieren:

    • .: __esc~2__
    • ..: __esc~2~2__

    Sie müssen das Zeichen . nur dann maskieren, wenn die ID genau . oder .. lautet. Für die Art-ID customers.info ist beispielsweise keine Maskierung erforderlich.

  • Wenn die Art oder Entitäts-ID ein numerischer Wert anstelle eines Stringwerts ist, müssen Sie die ID mit __idNUMERIC_VALUE__ maskieren. Das Pfadmuster für eine Entität vom Typ 111 und der Entitäts-ID 222 ist beispielsweise __id111__/__id222__.

  • Wenn Sie von Legacy-Cloud Datastore zu Firestore im Datastore-Modus migriert haben, enthält Ihre Datenbank möglicherweise alte IDs in einer Nicht-UTF8-Codierung. Diese IDs müssen mit dem Escapezeichen __bytesBASE64_ENCODING__ versehen werden. Ersetzen Sie BASE64_ENCODING durch die Base-64-Codierung der ID. Beispielsweise wird das Pfadmuster Task/{task} mit Escapezeichen für die Nicht-UTF8-Art-ID Task zu __bytesVGFzaw==__/{task}.

Beispielfunktionen

Im folgenden Beispiel wird veranschaulicht, wie Ereignisse im Datastore-Modus empfangen werden. Wenn Sie mit den Daten eines Ereignisses arbeiten möchten, sehen Sie sich die Felder value und old_value an.

  • value: Ein EntityResult-Objekt, das einen Entitäts-Snapshot vom Typ post-operation enthält. Dieses Feld wird bei Löschereignissen nicht ausgefüllt.
  • old_value: Ein EntityResult-Objekt, das einen Entitäts-Snapshot vor dem Vorgang enthält. Dieses Feld wird nur bei Aktualisierungs- und Löschereignissen ausgefüllt.

Java

Informationen zum Installieren und Verwenden der Clientbibliothek für den Datastore-Modus finden Sie unter Clientbibliotheken im Datastore-Modus. Weitere Informationen finden Sie in der Referenzdokumentation zur Java API im Datastore-Modus.

Richten Sie Standardanmeldedaten für Anwendungen ein, um sich im Datastore-Modus zu authentifizieren. Weitere Informationen finden Sie unter Authentifizierung für eine lokale Entwicklungsumgebung einrichten.

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

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

  @Override
  public void accept(CloudEvent event) throws InvalidProtocolBufferException {
    EntityEventData datastoreEventData = EntityEventData.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(datastoreEventData.getOldValue().toString());

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

Proto-Abhängigkeiten in die Quelle aufnehmen

Sie müssen die Datei data.proto im Datastore-Modus in das Quellverzeichnis für die Funktion aufnehmen. Diese Datei importiert die folgenden Proto-Dateien, die Sie auch in Ihr Quellverzeichnis aufnehmen müssen:

Verwenden Sie für die Abhängigkeiten dieselbe Verzeichnisstruktur. Platziere beispielsweise struct.proto innerhalb von google/protobuf.

Diese Dateien werden benötigt, um Ereignisdaten zu decodieren. Wenn Ihre Funktionsquelle diese Dateien nicht enthält, gibt sie bei der Ausführung einen Fehler zurück.

Ereignisattribute

Jedes Ereignis enthält Datenattribute mit Informationen zum Ereignis, z. B. zu dem Zeitpunkt, zu dem das Ereignis ausgelöst wurde. Firestore im Datastore-Modus fügt zusätzliche Daten über die vom Ereignis beteiligte Datenbank und Entität hinzu. So können Sie auf diese Attribute zugreifen:

Java
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 namespace: " + event.getExtension("namespace"));
logger.info("Database entity: " + event.getExtension("entity"));
// For withAuthContext events
logger.info("Auth information: " + event.getExtension("authid"));
logger.info("Auth information: " + event.getExtension("authtype"));

Funktion bereitstellen

Nutzer, die Cloud Functions bereitstellen, müssen die IAM-Rolle Cloud Functions-Entwickler oder eine Rolle mit denselben Berechtigungen haben. Siehe auch Zusätzliche Konfiguration für die Bereitstellung.

Sie können eine Funktion entweder über die gcloud CLI oder die Google Cloud Console bereitstellen. Im folgenden Beispiel wird die Bereitstellung mit der gcloud CLI veranschaulicht. Weitere Informationen zur Bereitstellung mit der Google Cloud Console finden Sie unter Cloud Functions-Funktionen bereitstellen.

  1. Aktivieren Sie Cloud Shell in der Google Cloud Console.

    Cloud Shell aktivieren

    Unten in der Google Cloud Console wird eine Cloud Shell-Sitzung gestartet und eine Eingabeaufforderung angezeigt. Cloud Shell ist eine Shell-Umgebung, in der das Google Cloud CLI bereits installiert ist und Werte für Ihr aktuelles Projekt bereits festgelegt sind. Das Initialisieren der Sitzung kann einige Sekunden dauern.

  2. Verwenden Sie den Befehl gcloud functions deploy, um eine Funktion bereitzustellen:

    gcloud functions deploy FUNCTION_NAME \
    --gen2 \
    --region=FUNCTION_LOCATION \
    --trigger-location=TRIGGER_LOCATION \
    --runtime=RUNTIME \
    --source=SOURCE_LOCATION \
    --entry-point=CODE_ENTRYPOINT \
    --trigger-event-filters="type=EVENT_FILTER_TYPE" \
    --trigger-event-filters="database=DATABASE" \
    --trigger-event-filters="namespace=NAMESPACE" \
    --trigger-event-filters-path-pattern="entity=ENTITY_OR_PATH" \
    

    Das erste Argument, FUNCTION_NAME, ist ein Name für Ihre bereitgestellte Funktion. Der Name muss mit einem Buchstaben beginnen, gefolgt von bis zu 62 Buchstaben, Ziffern, Bindestrichen oder Unterstrichen. Das letzte Zeichen muss ein Buchstabe oder eine Ziffer sein. Ersetzen Sie FUNCTION_NAME durch einen gültigen Funktionsnamen. Fügen Sie dann die folgenden Flags hinzu:

    • Das Flag --gen2 gibt an, dass Sie die Bereitstellung in Cloud Functions (2. Generation) vornehmen möchten. Wenn Sie dieses Flag weglassen, erfolgt die Bereitstellung in Cloud Functions (1. Generation).

    • Das Flag --region=FUNCTION_LOCATION gibt die Region an, in der die Funktion bereitgestellt werden soll.

      Zum Maximieren der Nähe legen Sie für FUNCTION_LOCATION eine Region in der Nähe Ihrer Firestore-Datenbank fest. Wenn sich Ihre Firestore-Datenbank an einem multiregionalen Standort befindet, legen Sie den Wert für Datenbanken in nam5 auf us-central1 und für Datenbanken in eur3 auf europe-west4 fest. Legen Sie für regionale Firestore-Standorte dieselbe Region fest.

    • Das Flag --trigger-location=TRIGGER_LOCATION gibt den Speicherort des Triggers an. Sie müssen für TRIGGER_LOCATION den Speicherort Ihrer Datenbank im Datastore-Modus festlegen.

    • Das Flag --runtime=RUNTIME gibt an, welche Sprachlaufzeit die Funktion verwendet. Cloud Functions unterstützt mehrere Laufzeiten. Weitere Informationen finden Sie unter Laufzeiten. Legen Sie für RUNTIME eine unterstützte Laufzeit fest.

    • Das Flag --source=SOURCE_LOCATION gibt den Speicherort des Quellcodes der Funktion an. Weitere Informationen dazu finden Sie hier:

      Legen Sie für SOURCE_LOCATION den Speicherort des Funktionsquellcodes fest.

    • Das Flag --entry-point=CODE_ENTRYPOINT gibt den Einstiegspunkt für die Funktion in Ihrem Quellcode an. Dies ist der Code, den Ihre Funktion ausführt, wenn sie ausgeführt wird. Sie müssen CODE_ENTRYPOINT auf einen Funktionsnamen oder einen voll qualifizierten Klassennamen festlegen, der im Quellcode vorhanden ist. Weitere Informationen finden Sie unter Funktionseinstiegspunkt.

    • Die Flags --trigger-event-filters definieren den Ereignisfilter, der den Triggertyp und die Entität oder den Pfad enthält, durch die die Ereignisse ausgelöst werden. Legen Sie die folgenden Attributwerte fest, um den Ereignisfilter zu definieren:

      • type=EVENT_FILTER_TYPE: Firestore unterstützt die folgenden Ereignistypen:

        • google.cloud.datastore.entity.v1.created: Das Ereignis wird gesendet, wenn eine Entität zum ersten Mal geschrieben wird.
        • google.cloud.datastore.entity.v1.updated: Das Ereignis wird gesendet, wenn eine Entität bereits vorhanden ist und sich ein Wert geändert hat.
        • google.cloud.datastore.entity.v1.deleted: Ereignis wird gesendet, wenn eine Entität gelöscht wird.
        • google.cloud.datastore.entity.v1.written: Ereignis wird gesendet, wenn eine Entität erstellt, aktualisiert oder gelöscht wird.
        • google.cloud.datastore.entity.v1.created.withAuthContext: Das Ereignis wird gesendet, wenn ein Dokument zum ersten Mal geschrieben wird und das Ereignis zusätzliche Authentifizierungsinformationen enthält.
        • google.cloud.datastore.entity.v1.updated.withAuthContext: Das Ereignis wird gesendet, wenn ein Dokument bereits vorhanden ist und sich ein Wert geändert hat. Enthält zusätzliche Authentifizierungsinformationen
        • google.cloud.datastore.entity.v1.deleted.withAuthContext: Das Ereignis wird gesendet, wenn ein Dokument gelöscht wird. Enthält zusätzliche Authentifizierungsinformationen
        • google.cloud.datastore.entity.v1.written.withAuthContext: Ereignis wird gesendet, wenn ein Dokument sowie ein Ereignis erstellt, aktualisiert oder gelöscht wird. Enthält zusätzliche Authentifizierungsinformationen

        Legen Sie für EVENT_FILTER_TYPE einen dieser Ereignistypen fest.

      • database=DATABASE: Firestore-Datenbank. Legen Sie für den Standarddatenbanknamen DATABASE auf (default) fest.

      • namespace=NAMESPACE: der Namespace der Datenbank. Legen Sie für den Standarddatenbanknamen NAMESPACE auf (default) fest. Entfernen Sie das Flag, damit es mit jedem Namespace übereinstimmt.

      • entity=ENTITY_OR_PATH: der Datenbankpfad, der beim Erstellen, Aktualisieren oder Löschen von Daten Ereignisse auslöst. Zulässige Werte für ENTITY_OR_PATH sind:

        • Gleich. Beispiel: --trigger-event-filters="entity='users/marie'"
        • Pfadmuster. Beispiel: --trigger-event-filters-path-pattern="entity='users/*'". Weitere Informationen finden Sie unter Informationen zu Pfadmustern.

      Sie können optional weitere Konfigurations-, Netzwerk- und Sicherheitsoptionen angeben, wenn Sie eine Funktion bereitstellen.

      Eine vollständige Referenz zum Bereitstellungsbefehl und seinen Flags finden Sie in der Dokumentation zu gcloud functions deploy.

Beispielbereitstellungen

Die folgenden Beispiele zeigen Bereitstellungen mit der Google Cloud CLI.

Stellen Sie eine Funktion für eine Datenbank in der Region us-west2 bereit:

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

Stellen Sie eine Funktion für eine Datenbank am multiregionalen Standort nam5 bereit:

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

Beschränkungen

Beachten Sie die folgenden Einschränkungen für Firestore-Trigger für Cloud Functions:

  • Für Cloud Functions (1. Generation) ist eine vorhandene „(Standard)-Datenbank im nativen Modus von Firestore erforderlich. Er unterstützt weder benannte Firestore-Datenbanken noch den Datastore-Modus. Verwenden Sie in solchen Fällen Cloud Functions (2nd gen), um Ereignisse zu konfigurieren.
  • Die Reihenfolge ist nicht garantiert. Schnelle Änderungen können Funktionsaufrufe in einer unvorhergesehenen Reihenfolge auslösen.
  • Ereignisse werden mindestens einmal übergeben. Ein einzelnes Ereignis kann aber zu mehreren Funktionsaufrufen führen. Vermeiden Sie die Abhängigkeit von genau einmal vorkommenden Verfahren und schreiben Sie idempotente Funktionen.
  • Firestore im Datastore-Modus erfordert Cloud Functions (2nd gen). Cloud Functions (1st Gen) unterstützt den Datastore-Modus nicht.
  • Ein Trigger ist einer einzelnen Datenbank zugeordnet. Sie können keinen Trigger erstellen, der mit mehreren Datenbanken übereinstimmt.
  • Durch das Löschen einer Datenbank werden nicht automatisch die Trigger für diese Datenbank gelöscht. Der Trigger liefert keine Ereignisse mehr, bleibt aber bestehen, bis Sie den Trigger löschen.
  • Wenn ein übereinstimmendes Ereignis die maximale Anfragegröße überschreitet, wird das Ereignis möglicherweise nicht an Cloud Functions (1st gen) übertragen.
    • Ereignisse, die aufgrund der Größe der Anfrage nicht zugestellt werden, werden in Plattformlogs protokolliert und auf die Lognutzung für das Projekt angerechnet.
    • Sie finden diese Logs im Log-Explorer mit der Meldung "Ereignis kann nicht an die Cloud Functions-Funktion gesendet werden, da die Größe das Limit für die 1. Generation überschreitet..." mit dem Schweregrad error. Sie finden den Funktionsnamen unter dem Feld functionName. Wenn das Feld receiveTimestamp noch innerhalb einer Stunde ab jetzt ist, können Sie den tatsächlichen Ereignisinhalt ableiten. Lesen Sie dazu das betreffende Dokument mit einem Snapshot vor und nach dem Zeitstempel.
    • Um eine solche Uploadhäufigkeit zu vermeiden, können Sie Folgendes tun:
      • Zu Cloud Functions (2nd gen) migrieren und upgraden
      • Dokument verkleinern
      • Betreffende Cloud Functions-Funktionen löschen
    • Sie können die Protokollierung selbst mithilfe von Ausschlüssen deaktivieren. Die betreffenden Ereignisse werden jedoch nicht gesendet.

Standorte für Eventarc und Firestore im Datastore-Modus

Eventarc unterstützt keine Mehrfachregionen für Firestore-Ereignistrigger. Sie können jedoch Trigger für Firestore-Datenbanken an multiregionalen Standorten erstellen. Eventarc ordnet multiregionale Firestore-Standorte den folgenden Eventarc-Regionen zu:

Firestore (multiregional) Eventarc-Region
nam5 us-central1
eur3 europe-west4

Nächste Schritte