Datastore mit Cloud Functions (2nd gen) erweitern

Mit Cloud Run-Funktionen 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 für Firestore im Datastore-Modus, mit denen Sie Cloud Run Functions (2. Generation) mit Ereignissen in Firestore im Datastore-Modus verknüpfen können:

Ereignistyp Trigger
google.cloud.datastore.entity.v1.created Wird ausgelöst, wenn ein Element 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 Entspricht created, fügt aber Authentifizierungsinformationen hinzu.
google.cloud.datastore.entity.v1.updated.withAuthContext Entspricht updated, fügt aber Authentifizierungsinformationen hinzu.
google.cloud.datastore.entity.v1.deleted.withAuthContext Entspricht deleted, fügt aber Authentifizierungsinformationen hinzu.
google.cloud.datastore.entity.v1.written.withAuthContext Entspricht written, fügt aber Authentifizierungsinformationen hinzu.

Ereignistrigger im Datastore-Modus reagieren nur auf Entitätsänderungen. Die Aktualisierung einer Entität im Datastore-Modus, bei der die Daten unverändert bleiben (also ohne Schreibvorgang), generiert kein Aktualisierungs- oder Schreibereignis. Sie können keine Ereignisse nur für bestimmte Properties generieren.

Authentifizierungskontext in das Ereignis einschließen

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

Entitätsausgelöste Funktion schreiben

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

  • einen Triggerereignistyp
  • einen Triggerereignisfilter, um die mit der Funktion verknüpften Entitäten auszuwählen
  • den auszuführenden Funktionscode

Triggerereignisfilter

Wenn Sie einen Ereignisfilter angeben, können Sie entweder eine exakte 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 Platzhalter, * oder **, um auf Änderungen an 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 Übereinstimmungen mit einem einzelnen Segment (*) können Sie auch eine benannte Erfassungsgruppe wie users/{userId} verwenden.

In der folgenden Tabelle sind gültige Pfadmuster aufgeführt:

Muster Beschreibung
users/* oder users/{userId} Stimmt mit allen Entitäten der Art users überein. Stimmt nicht mit der Ebene der untergeordneten Entitäten wie /users/marie/messages/33e2IxYBD9enzS50SJ68 überein
users/** Führt zu Übereinstimmungen mit allen Entitäten vom Typ users und allen untergeordneten Entitäten wie /users/marie/messages/33e2IxYBD9enzS50SJ68.

Weitere Informationen zu Pfadmustern finden Sie unter Eventarc-Pfadmuster.

Ihr Trigger muss immer auf ein Element 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.

Zeichenmaskierung

In diesem Abschnitt werden Situationen beschrieben, in denen Sie Zeichen in Art-IDs und Entitäts-IDs maskieren müssen. Durch das Entkommentieren eines Zeichens kann der Ereignisfilter die ID richtig interpretieren.

  • Wenn eine Art-ID oder Entitäts-ID das Zeichen ~ oder / enthält, müssen Sie die ID in Ihrem Ereignisfilter mit einem Escape-Zeichen versehen. Verwenden Sie das Format __escENCODED_ID__, um eine ID zu escapen. Ersetzen Sie ENCODED_ID durch eine Art-ID oder eine Entitäts-ID, bei der alle Zeichen ~ und / durch ihre Codierungs-IDs ersetzt werden. Die Codierungs-IDs lauten:

    • ~: ~0
    • /: ~1

    Aus der Art-ID user/profile wird beispielsweise __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 escapen:

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

    Das Zeichen „.“ muss nur dann entkommentiert werden, wenn die ID genau . oder .. ist. Für die Art-ID customers.info ist beispielsweise kein Escapezeichen erforderlich.

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

  • Wenn Sie von Legacy Cloud Datastore zu Firestore im Datastore-Modus migriert sind, enthält Ihre Datenbank möglicherweise Legacy-IDs in einer anderen Codierung als UTF-8. Diese IDs müssen mit __bytesBASE64_ENCODING__ vorangestellt werden. Ersetzen Sie BASE64_ENCODING durch die Base64-Codierung der ID. Beispiel: Das Pfadmuster Task/{task} mit Escape-Sequenz für die nicht UTF-8-Zeichencodierte Art-ID Task wird zu __bytesVGFzaw==__/{task}.

Beispielfunktionen

Im folgenden Beispiel wird gezeigt, wie Ereignisse im Datastore-Modus empfangen werden. Die Daten zu einem Ereignis finden Sie in den Feldern value und old_value.

  • value: Ein EntityResult-Objekt, das einen Entitäts-Snapshot nach dem Vorgang enthält. Dieses Feld wird für Löschereignisse nicht ausgefüllt.
  • old_value: Ein EntityResult-Objekt, das einen Entitäts-Snapshot vor dem Vorgang enthält. Dieses Feld wird nur für Aktualisierungs- und Löschereignisse ausgefüllt.

Java

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

Richten Sie die Standardanmeldedaten für Anwendungen ein, um sich beim 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 einbinden

Sie müssen die Datei Datastore-Modus data.proto in das Quellverzeichnis Ihrer Funktion aufnehmen. Diese Datei importiert die folgenden Protodateien, die Sie auch in Ihr Quellverzeichnis aufnehmen müssen:

Verwenden Sie für die Abhängigkeiten dieselbe Verzeichnisstruktur. Platzieren Sie beispielsweise struct.proto in google/protobuf.

Diese Dateien sind erforderlich, um Ereignisdaten zu decodieren. Wenn Ihre Funktionsquelle diese Dateien nicht enthält, wird beim Ausführen ein Fehler zurückgegeben.

Ereignisattribute

Jedes Ereignis enthält Datenattribute mit Informationen zum Ereignis, z. B. zum Zeitpunkt, zu dem es ausgelöst wurde. Im Firestore im Datastore-Modus werden zusätzliche Daten zur Datenbank und zur Entität hinzugefügt, die am Ereignis beteiligt sind. So greifen Sie auf diese Attribute zu:

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 Run Functions bereitstellen, müssen die IAM-Rolle Cloud Run-Entwickler oder eine Rolle mit denselben Berechtigungen haben. Siehe auch Zusätzliche Konfiguration für die Bereitstellung.

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

  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. 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 Run Functions (2. Generation) vornehmen möchten. Wenn Sie dieses Flag weglassen, erfolgt die Bereitstellung in Cloud Run Functions (1. Generation).

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

      Um die Nähe zu maximieren, legen Sie FUNCTION_LOCATION auf 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 Trigger an. Sie müssen TRIGGER_LOCATION auf den Speicherort Ihrer Datenbank im Datastore-Modus festlegen.

    • Das Flag --runtime=RUNTIME gibt an, welche Sprachlaufzeit die Funktion verwendet. Cloud Run-Funktionen unterstützen 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 finden Sie hier:

      Legen Sie SOURCE_LOCATION auf den Speicherort des Quellcodes der Funktion fest.

    • Das Flag --entry-point=CODE_ENTRYPOINT gibt den Einstiegspunkt für die Funktion in Ihrem Quellcode an. Dies ist der Code, der beim Ausführen der Funktion ausgeführt wird. Sie müssen CODE_ENTRYPOINT auf einen Funktionsnamen oder einen voll qualifizierten Klassennamen festlegen, der in Ihrem 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, die bzw. der die Ereignisse auslöst. Legen Sie die folgenden Attributwerte fest, um Ihren Ereignisfilter zu definieren:

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

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

        Legen Sie EVENT_FILTER_TYPE auf einen dieser Ereignistypen fest.

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

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

      • entity=ENTITY_OR_PATH: der Datenbankpfad, der Ereignisse auslöst, wenn Daten erstellt, aktualisiert oder gelöscht werden. 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.

Beispielimplementierungen

In den folgenden Beispielen werden Bereitstellungen mit der Google Cloud CLI veranschaulicht.

Funktion für eine Datenbank in der Region us-west2 bereitstellen:

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}'"

So stellen Sie eine Funktion für eine Datenbank in der Multi-Region 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 Run Functions:

  • Cloud Run Functions (1. Generation) erfordert eine vorhandene „(default)“-Datenbank im nativen Firestore-Modus. Es unterstützt keine benannten Firestore-Datenbanken und keinen Datastore-Modus. Verwenden Sie in solchen Fällen Cloud Run Functions (2. Generation), 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 Run Functions (2. Generation). Cloud Run Functions (1. Generation) unterstützt den Datastore-Modus nicht.
  • Ein Trigger ist mit einer einzelnen Datenbank verknüpft. Sie können keinen Trigger erstellen, der mit mehreren Datenbanken übereinstimmt.
  • Wenn Sie eine Datenbank löschen, werden nicht automatisch die Trigger für diese Datenbank gelöscht. Der Trigger sendet keine Ereignisse mehr, bleibt aber bestehen, bis Sie ihn löschen.
  • Wenn ein übereinstimmendes Ereignis die maximale Anfragegröße überschreitet, wird es möglicherweise nicht an Cloud Run Functions der 1. Generation gesendet.
    • Ereignisse, die aufgrund der Anfragegröße nicht gesendet wurden, werden in Plattform-Logs protokolliert und in die Lognutzung für das Projekt einbezogen.
    • 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. Den Funktionsnamen finden Sie im Feld functionName. Wenn das Feld receiveTimestamp noch eine Stunde gültig ist, können Sie den tatsächlichen Ereignisinhalt ableiten, indem Sie das betreffende Dokument mit einem Snapshot vor und nach dem Zeitstempel lesen.
    • So können Sie das vermeiden:
      • Migrieren und Upgrade auf Cloud Run Functions (2. Generation)
      • Dokument verkleinern
      • Die betreffenden Cloud Run Functions-Funktionen löschen
    • Sie können die Protokollierung selbst mithilfe von Ausschlüssen deaktivieren. Die betreffenden Ereignisse werden jedoch weiterhin nicht gesendet.

Standorte für Eventarc und Firestore im Datastore-Modus

Eventarc unterstützt keine Mehrfachregionen für Firestore-Ereignistrigger. Sie können jedoch weiterhin Trigger für Firestore-Datenbanken an Standorten mit mehreren Regionen erstellen. In Eventarc werden Firestore-Standorte mit mehreren Regionen den folgenden Eventarc-Regionen zugeordnet:

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

Nächste Schritte