Étendre Datastore avec Cloud Functions (2nd gen)

Avec les fonctions Cloud Run et Eventarc, vous pouvez déployer du code pour gérer les événements déclenchés par les modifications apportées à votre base de données Firestore en mode Datastore. Vous pouvez ainsi ajouter des fonctionnalités côté serveur sans avoir à gérer vos propres serveurs.

Déclencheurs du mode Datastore

Eventarc est compatible avec les déclencheurs d'événements Firestore en mode Datastore suivants pour vous permettre de créer des gestionnaires de fonctions Cloud Run (2e génération) associés aux événements Firestore en mode Datastore:

Type d'événement Déclencheur
google.cloud.datastore.entity.v1.created Déclenché lorsqu'une entité est écrite pour la première fois.
google.cloud.datastore.entity.v1.updated Déclenché lorsqu'une entité existe déjà et qu'une valeur y a été modifiée.
google.cloud.datastore.entity.v1.deleted Déclenché lorsqu'une entité est supprimée.
google.cloud.datastore.entity.v1.written Déclenché lorsque created, updated ou deleted est déclenché.
google.cloud.datastore.entity.v1.created.withAuthContext Identique à created, mais ajoute des informations d'authentification.
google.cloud.datastore.entity.v1.updated.withAuthContext Identique à updated, mais ajoute des informations d'authentification.
google.cloud.datastore.entity.v1.deleted.withAuthContext Identique à deleted, mais ajoute des informations d'authentification.
google.cloud.datastore.entity.v1.written.withAuthContext Identique à written, mais ajoute des informations d'authentification.

Les déclencheurs d'événements en mode Datastore ne répondent qu'aux modifications d'entités. Une mise à jour d'une entité en mode Datastore où les données restent inchangées (écriture no-op) ne génère pas d'événement de mise à jour ou d'écriture. Vous ne pouvez pas générer d'événements que pour des propriétés spécifiques.

Inclure le contexte d'authentification dans l'événement

Pour inclure des informations d'authentification supplémentaires sur l'événement, utilisez un déclencheur d'événement avec l'extension withAuthContext. Cette extension ajoute des informations supplémentaires sur le principal qui a déclenché l'événement. Il ajoute les attributs authtype et authid en plus des informations renvoyées dans l'événement de base. Pour en savoir plus sur les valeurs d'attribut, consultez la documentation de référence sur authcontext.

Écrire une fonction déclenchée par une entité

Pour écrire une fonction qui répond aux événements Firestore en mode Datastore, préparez-vous à spécifier les éléments suivants lors du déploiement:

  • un type d'événement déclencheur
  • un filtre d'événement de déclencheur pour sélectionner les entités associées à la fonction
  • le code de la fonction à exécuter ;

Filtres des événements déclencheurs

Lorsque vous spécifiez un filtre d'événement, vous pouvez spécifier une correspondance d'entité exacte ou un format de chemin d'accès. Utilisez un format de chemin d'accès pour faire correspondre plusieurs entités avec les caractères génériques * ou **.

Par exemple, vous pouvez spécifier une correspondance d'entité exacte pour répondre aux modifications apportées à l'entité suivante:

users/marie

Utilisez des caractères génériques, * ou **, pour répondre aux modifications apportées aux entités correspondant à un format. Le caractère générique * correspond à un seul segment, tandis que le caractère générique multisegment ** correspond à zéro ou plusieurs segments du format.

Pour les correspondances d'un seul segment (*), vous pouvez également utiliser un groupe de capture nommé, tel que users/{userId}.

Le tableau suivant présente des exemples de formats de chemin d'accès valides:

Modèle Description
users/* ou users/{userId} Correspond à toutes les entités de type users. Ne correspond pas au niveau des entités descendantes, comme /users/marie/messages/33e2IxYBD9enzS50SJ68
users/** Correspond à toutes les entités de type users et à toutes les entités descendantes telles que /users/marie/messages/33e2IxYBD9enzS50SJ68

Pour en savoir plus sur les formats de chemin d'accès, consultez la section Formats de chemin d'accès Eventarc.

Votre déclencheur doit toujours pointer vers une entité, même si vous utilisez un caractère générique. Consultez les exemples suivants :

  • users/{userId=*}/{messages=*} n'est pas valide, car {messages=*} est un ID de type.

  • users/{userId=*}/{messages}/{messageId=*} est valide, car {messageId=*} pointe toujours vers une entité.

Échappement des caractères

Cette section décrit les situations dans lesquelles vous devez échapper les caractères dans les ID de genre et les ID d'entité. L'échappement d'un caractère permet au filtre d'événement d'interpréter correctement l'ID.

  • Si un ID de type ou d'entité inclut un caractère ~ ou /, vous devez échapper l'ID dans votre filtre d'événement. Pour échapper à un ID, utilisez le format __escENCODED_ID__. Remplacez ENCODED_ID par un ID de type ou d'entité dans lequel tous les caractères ~ et / sont remplacés par leurs ID d'encodage, qui sont les suivants:

    • ~ : ~0
    • / : ~1

    Par exemple, l'ID de type user/profile devient __escusers~1profile__. Voici un exemple de modèle de chemin avec cet ID de type : __escusers~1profile__/{userId}.

  • Si vous utilisez l'ID de type ou l'ID d'entité de . ou .. dans votre filtre d'événements, vous devez échapper à l'ID comme suit:

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

    Vous ne devez échapper le caractère . que si l'ID est exactement . ou ... Par exemple, l'ID de type customers.info ne nécessite pas d'échappement.

  • Si votre type ou votre ID d'entité est une valeur numérique au lieu d'une valeur de chaîne, vous devez échapper l'ID avec __idNUMERIC_VALUE__. Par exemple, le format de chemin d'accès d'une entité de type 111 et d'ID d'entité 222 est __id111__/__id222__.

  • Si vous êtes passé de l'ancien Cloud Datastore à Firestore en mode Datastore, votre base de données peut contenir d'anciens ID encodés en dehors d'UTF-8. Vous devez échapper ces ID avec __bytesBASE64_ENCODING__. Remplacez BASE64_ENCODING par l'encodage base64 de l'ID. Par exemple, le format de chemin d'accès Task/{task} avec échappement pour l'ID de type non UTF-8 Task devient __bytesVGFzaw==__/{task}.

Exemples de fonctions

L'exemple suivant montre comment recevoir des événements en mode Datastore. Pour travailler avec les données impliquées dans un événement, examinez les champs value et old_value.

  • value: objet EntityResult contenant un instantané d'entité après l'opération. Ce champ n'est pas renseigné pour les événements de suppression.
  • old_value: objet EntityResult contenant un instantané d'entité avant l'opération. Ce champ n'est renseigné que pour les événements de mise à jour et de suppression.

Java

Pour savoir comment installer et utiliser la bibliothèque cliente pour le mode Datastore, consultez la section Bibliothèques clientes en mode Datastore. Pour en savoir plus, consultez la documentation de référence de l'API Java en mode Datastore.

Pour vous authentifier auprès du mode Datastore, configurez les Identifiants par défaut de l'application. Pour en savoir plus, consultez Configurer l'authentification pour un environnement de développement local.

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

Inclure les dépendances proto dans votre source

Vous devez inclure le fichier data.proto pour le mode Datastore dans le répertoire source de votre fonction. Ce fichier importe les protos suivants, que vous devez également inclure dans votre répertoire source:

Utilisez la même structure de répertoire pour les dépendances. Par exemple, placez struct.proto dans google/protobuf.

Ces fichiers sont nécessaires pour décoder les données d'événement. Si la source de votre fonction n'inclut pas ces fichiers, une erreur est renvoyée lors de son exécution.

Attributs d'événement

Chaque événement inclut des attributs de données qui contiennent des informations sur l'événement, telles que l'heure à laquelle il s'est déclenché. Firestore en mode Datastore ajoute des données supplémentaires sur la base de données et l'entité impliquées dans l'événement. Pour y accéder, procédez comme suit:

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

Déployer une fonction

Les utilisateurs qui déploient des fonctions Cloud Run doivent disposer du rôle IAM Cloud Run functions Developer (Développeur Cloud Run Functions) ou d'un rôle comprenant les mêmes autorisations. Consultez également la section Configuration supplémentaire pour le déploiement.

Vous pouvez déployer une fonction à l'aide de la gcloud CLI ou de la console Google Cloud. L'exemple ci-dessous illustre le déploiement avec gcloud CLI. Pour en savoir plus sur le déploiement avec la console Google Cloud, consultez la section Déployer des fonctions Cloud Run.

  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. Exécutez la commande gcloud functions deploy pour déployer une fonction :

    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" \
    

    Le premier argument, FUNCTION_NAME, est le nom de la fonction déployée. Le nom de la fonction doit commencer par une lettre suivie de 62 caractères au maximum (lettres, chiffres, traits d'union ou traits de soulignement) et doit se terminer par une lettre ou un chiffre. Remplacez FUNCTION_NAME par un nom de fonction valide. Ajoutez ensuite les indicateurs suivants:

    • L'option --gen2 spécifie que vous souhaitez déployer sur Cloud Run Functions (2e génération). Si vous omettez cette option, le déploiement sur Cloud Run Functions (1re génération) sera effectué.

    • L'option --region=FUNCTION_LOCATION spécifie la région dans laquelle déployer votre fonction.

      Pour maximiser la proximité, définissez FUNCTION_LOCATION sur une région à proximité de votre base de données Firestore. Si votre base de données Firestore se trouve dans un emplacement multirégional, définissez la valeur sur us-central1 pour les bases de données dans nam5 et sur europe-west4 pour les bases de données dans eur3. Pour les emplacements Firestore régionaux, définissez la même région.

    • L'option --trigger-location=TRIGGER_LOCATION spécifie l'emplacement du déclencheur. Vous devez définir TRIGGER_LOCATION sur l'emplacement de votre base de données en mode Datastore.

    • L'option --runtime=RUNTIME spécifie l'environnement d'exécution de langage qui est utilisé par votre fonction. Cloud Run Functions accepte plusieurs environnements d'exécution. Pour en savoir plus, consultez la section Environnements d'exécution. Définissez RUNTIME sur un environnement d'exécution compatible.

    • L'option --source=SOURCE_LOCATION spécifie l'emplacement du code source de votre fonction. Pour en savoir plus, consultez les pages suivantes:

      Définissez SOURCE_LOCATION sur l'emplacement du code source de votre fonction.

    • L'option --entry-point=CODE_ENTRYPOINT spécifie le point d'entrée de votre fonction dans votre code source. Il s'agit du code exécuté par votre fonction lorsqu'elle s'exécute. Vous devez définir CODE_ENTRYPOINT sur un nom de fonction ou un nom de classe complet qui existe dans votre code source. Pour en savoir plus, consultez la section Point d'entrée de fonction.

    • Les indicateurs --trigger-event-filters définissent le filtre d'événements, qui inclut le type de déclencheur et l'entité ou le chemin qui déclenche les événements. Définissez les valeurs d'attribut suivantes pour définir votre filtre d'événements:

      • type=EVENT_FILTER_TYPE: Firestore accepte les types d'événements suivants:

        • google.cloud.datastore.entity.v1.created: l'événement est envoyé lorsqu'une entité est écrite pour la première fois.
        • google.cloud.datastore.entity.v1.updated: l'événement est envoyé lorsqu'une entité existe déjà et qu'une valeur y a été modifiée.
        • google.cloud.datastore.entity.v1.deleted: l'événement est envoyé lorsqu'une entité est supprimée.
        • google.cloud.datastore.entity.v1.written: l'événement est envoyé lorsqu'une entité est créée, mise à jour ou supprimée.
        • google.cloud.datastore.entity.v1.created.withAuthContext: l'événement est envoyé lorsqu'un document est écrit pour la première fois et qu'il inclut des informations d'authentification supplémentaires.
        • google.cloud.datastore.entity.v1.updated.withAuthContext: l'événement est envoyé lorsqu'un document existe déjà et qu'une valeur y a été modifiée. Inclut des informations d'authentification supplémentaires
        • google.cloud.datastore.entity.v1.deleted.withAuthContext: l'événement est envoyé lorsqu'un document est supprimé. Inclut des informations d'authentification supplémentaires
        • google.cloud.datastore.entity.v1.written.withAuthContext: l'événement est envoyé lorsqu'un document est créé, mis à jour ou supprimé. Inclut des informations d'authentification supplémentaires

        Définissez EVENT_FILTER_TYPE sur l'un de ces types d'événements.

      • database=DATABASE : base de données Firestore. Pour spécifier le nom de la base de données par défaut, définissez DATABASE sur (default).

      • namespace=NAMESPACE: espace de noms de la base de données. Pour le nom de la base de données par défaut, définissez NAMESPACE sur (default). Supprimez l'indicateur pour faire correspondre n'importe quel espace de noms.

      • entity=ENTITY_OR_PATH: chemin d'accès de la base de données qui déclenche des événements lorsque des données sont créées, mises à jour ou supprimées. Les valeurs acceptées pour ENTITY_OR_PATH sont les suivantes:

        • Égal à. Par exemple : --trigger-event-filters="entity='users/marie'"
        • Format de chemin d'accès. Exemple : --trigger-event-filters-path-pattern="entity='users/*'" Pour en savoir plus, consultez la page Comprendre les formats de chemin d'accès.

      Vous pouvez éventuellement spécifier des options supplémentaires de configuration, de mise en réseau et de sécurité lorsque vous déployez une fonction.

      Pour en savoir plus sur la commande de déploiement et ses options, consultez la documentation sur gcloud functions deploy.

Exemples de déploiements

Les exemples suivants illustrent les déploiements avec la Google Cloud CLI.

Déployez une fonction pour une base de données dans la région us-west2:

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

Déployer une fonction pour une base de données dans la zone multirégionale nam5:

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

Limites

Notez les limites suivantes concernant les déclencheurs Firestore pour Cloud Run Functions :

  • Cloud Run Functions (1re génération) nécessite une base de données "(default)" existante en mode natif Firestore. La solution n'est pas compatible avec les bases de données nommées Firestore ni avec le mode Datastore. Veuillez utiliser Cloud Run Functions (2nd gen) pour configurer des événements dans ce cas.
  • L'ordre n'est pas garanti. Les modifications rapides peuvent déclencher des appels de fonctions dans un ordre inattendu.
  • Bien que les événements soient diffusés une fois au moins, un même événement peut produire plusieurs appels de fonction. Évitez de dépendre de procédés dits "exactement une fois" et écrivez des fonctions idempotentes.
  • Firestore en mode Datastore nécessite Cloud Run Functions (2nd gen). Cloud Run Functions (1re génération) n'est pas compatible avec le mode Datastore.
  • Un déclencheur est associé à une seule base de données. Vous ne pouvez pas créer un déclencheur qui correspond à plusieurs bases de données.
  • La suppression d'une base de données ne supprime pas automatiquement les déclencheurs de cette base de données. Le déclencheur cesse de diffuser des événements, mais continue d'exister jusqu'à ce que vous le supprimiez.
  • Si un événement correspondant dépasse la taille maximale de requête, il risque de ne pas être distribué à Cloud Run Functions (1re génération).
    • Les événements non distribués en raison de la taille de la requête sont consignés dans les journaux de plate-forme et sont comptabilisés dans l'utilisation des journaux du projet.
    • Vous trouverez ces journaux dans l'explorateur de journaux avec le message "Event cannot deliver to Cloud function due to size exceeding the limit for 1st gen..." (l'événement ne peut pas être distribué à la fonction Cloud, car sa taille dépasse la limite pour la 1re génération...) de gravité error. Vous trouverez le nom de la fonction dans le champ functionName. Si le champ receiveTimestamp date de moins d'une heure, vous pouvez déduire le contenu réel de l'événement en lisant le document en question avec un instantané avant et après le code temporel.
    • Pour éviter une telle cadence, vous pouvez :
      • Migrer et passer à Cloud Run Functions (2nd gen)
      • Réduire la taille du document
      • Supprimer les fonctions Cloud Run Functions en question
    • Vous pouvez désactiver la journalisation proprement dite à l'aide d'exclusions, mais notez que les événements mis en cause ne seront toujours pas distribués.

Emplacements Eventarc et Firestore en mode Datastore

Eventarc n'est pas compatible avec les emplacements multirégionaux pour les déclencheurs d'événements Firestore, mais vous pouvez toujours créer des déclencheurs pour les bases de données Firestore dans des emplacements multirégionaux. Eventarc mappe les emplacements multirégionaux Firestore aux régions Eventarc suivantes:

Firestore – Plusieurs régions Région Eventarc
nam5 us-central1
eur3 europe-west4

Étape suivante