使用 Cloud Functions (第 2 代) 扩展 Datastore

借助 Cloud Functions 和 Eventarc,你可以将代码部署到 处理由 Datastore 模式 Firestore 数据库更改触发的事件。这个 可让您在不运行自己的服务器的情况下添加服务器端功能。

Datastore 模式触发器

Eventarc 支持以下 Datastore 模式 Firestore 事件 触发器允许您创建 Datastore 模式 Firestore 事件:

事件类型 触发器
google.cloud.datastore.entity.v1.created 首次写入实体时触发。
google.cloud.datastore.entity.v1.updated 当实体已存在并且其任何值发生了更改时触发。
google.cloud.datastore.entity.v1.deleted 在删除实体时触发。
google.cloud.datastore.entity.v1.written 在触发 createdupdateddeleted 时触发。
google.cloud.datastore.entity.v1.created.withAuthContext created 相同,但添加了身份验证信息。
google.cloud.datastore.entity.v1.updated.withAuthContext updated 相同,但添加了身份验证信息。
google.cloud.datastore.entity.v1.deleted.withAuthContext deleted 相同,但添加了身份验证信息。
google.cloud.datastore.entity.v1.written.withAuthContext written 相同,但添加了身份验证信息。

Datastore 模式事件触发器仅响应 实体更改。更新 Datastore 模式实体 保持不变(无操作写入)不会生成更新或写入事件。您 无法仅针对特定媒体资源生成事件。

在事件中包含身份验证上下文

如需添加有关该事件的其他身份验证信息,请使用事件 扩展程序为 withAuthContext 的触发器。此附加信息可将 触发事件的主账号的相关信息。它会将 authtypeauthid 属性以及在 事件。请参阅 如需详细了解属性值,请参阅 authcontext 参考文档。

编写实体触发的函数

如需编写一个函数来响应 Datastore 模式 Firestore 事件, 准备在部署期间指定以下内容:

  • 触发器事件类型
  • 一个触发器事件过滤条件,用于选择与函数关联的实体
  • 要运行的函数代码

触发事件过滤条件

指定事件过滤器时,您可以指定 匹配或路径模式。使用路径模式将多个实体与 通配符 ***

例如,您可以指定完全匹配的实体以响应对 以下实体:

users/marie

使用通配符(***)响应实体中的更改 特定字词。* 通配符匹配单个片段,以及 ** 多段通配符匹配模式中的零个或多个段。

对于单段匹配 (*),您还可以使用已命名的捕获组,例如 名称:users/{userId}

下表演示了有效的路径模式:

模式 说明
users/*users/{userId} 匹配 users 种类的所有实体。与后代实体级别(如 /users/marie/messages/33e2IxYBD9enzS50SJ68)不匹配
users/** 匹配 users 种类的所有实体以及类似的所有后代实体 /users/marie/messages/33e2IxYBD9enzS50SJ68

如需详细了解路径模式,请参阅 Eventarc 路径模式

您的触发器必须始终指向某个实体,即使您使用通配符也是如此。 请参见以下示例:

  • users/{userId=*}/{messages=*} 无效,原因是 {messages=*} 是种类 ID。

  • users/{userId=*}/{messages}/{messageId=*} 有效,因为 {messageId=*} 始终指向实体。

字符转义

本部分介绍了在使用 种类 ID 和实体 ID。转义字符可让事件正确过滤 解读 ID。

  • 如果种类 ID 或实体 ID 包含 ~/ 字符,则必须 对事件过滤器中的 ID 进行转义。要对 ID 进行转义,请使用以下格式: __escENCODED_ID__。 将 ENCODED_ID 替换为包含所有 ~ 的种类 ID 或实体 ID / 个字符替换为其编码 ID,如下所示:

    • ~~0
    • /~1

    例如,种类 ID user/profile 会变为 __escusers~1profile__。一个 具有此种类 ID 的示例路径模式为 __escusers~1profile__/{userId}

  • 如果您在事件过滤器中使用 ... 的种类 ID 或实体 ID, 您必须按如下方式对该 ID 进行转义:

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

    仅当 ID 为 ... 时,您才需要对 . 字符进行转义。 例如,种类 ID customers.info 不需要转义。

  • 如果您的种类或实体 ID 是数值而不是字符串值, 您必须使用 __idNUMERIC_VALUE__ 对该 ID 进行转义。 例如,种类为 111 且实体 ID 为 222 的实体的路径模式 为 __id111__/__id222__

  • 如果您从旧版 Cloud Datastore 迁移 导出到 Datastore 模式 Firestore,您的数据库可能会包含采用非 UTF8 编码的旧版 ID。 您必须使用 __bytesBASE64_ENCODING__ 对这些 ID 进行转义。 将 BASE64_ENCODING 替换为 ID 的 base-64 编码。对于 例如,对非 UTF8 种类 ID 进行转义的路径模式 Task/{task} Task 会变为 __bytesVGFzaw==__/{task}

示例函数

以下示例演示了如何接收 Datastore 模式事件。 如需处理事件中涉及的数据,请查看 valueold_value 字段。

  • value:包含操作后实体快照的 EntityResult 对象。 对于删除事件,不会填充此字段。
  • old_value:包含操作前实体的 EntityResult 对象 快照。系统只会针对更新和删除事件填充此字段。

Java

如需了解如何安装和使用适用于 Datastore 模式的客户端库,请参阅 Datastore 模式客户端库。 有关详情,请参阅 Datastore 模式 Java API 参考文档

如需向 Datastore 模式进行身份验证,请设置应用默认凭据。 如需了解详情,请参阅为本地开发环境设置身份验证

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 依赖项

您必须添加 Datastore 模式 data.proto 文件(位于函数源目录中)。此文件会导入以下内容: protos,您还必须将其包含在源目录中:

为依赖项使用相同的目录结构。例如,地点 google/protobuf中的struct.proto

需要使用这些文件才能对事件数据进行解码。如果函数来源 不包含这些文件,则会在运行时返回错误。

事件属性

每个事件都包含数据属性 其中包含事件相关信息(例如事件触发时间)。 Datastore 模式 Firestore 会添加有关数据库和实体的额外数据 相关事件。您可以按如下方式访问这些属性:

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

部署函数

部署 Cloud Functions 的用户必须具有 Cloud Functions Developer IAM 角色或具有提供相同权限的其他角色。另请参阅其他部署配置

您可以使用 gcloud CLI 部署函数 或 Google Cloud 控制台以下示例演示了如何使用 gcloud CLI如需详细了解如何使用 Google Cloud 控制台进行部署, 请参阅部署 Cloud Functions 函数

  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. 使用 gcloud functions deploy 命令部署函数:

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

    第一个参数 FUNCTION_NAME 是已部署函数的名称。函数名称必须以字母开头 后面最多可跟 62 个字母、数字、连字符或下划线,而且必须以 以字母或数字开头。将 FUNCTION_NAME 替换为有效的 函数名称。然后,添加以下标志:

    • --gen2 标志用于指定要部署到 Cloud Functions (第 2 代)。省略 此标志会导致部署到 Cloud Functions (第 1 代)。

    • --region=FUNCTION_LOCATION 标志 指定要部署函数的区域。

      为了尽可能地接近,请将 FUNCTION_LOCATION 设置为附近的区域 Firestore 数据库。如果您的 Firestore 数据库是 在多区域位置,请将数据库的值设置为 us-central1 nam5 中的数据库,以及 eur3 中的数据库的 europe-west4。对于区域级 Firestore 位置,设置为同一区域。

    • --trigger-location=TRIGGER_LOCATION 标志指定触发器的位置。 您必须将 TRIGGER_LOCATION 设置为 Datastore 模式数据库的位置。

    • --runtime=RUNTIME 标志指定函数使用的语言运行时。Cloud Functions 支持多个运行时。请参阅 运行时。 将 RUNTIME 设置为受支持的运行时。

    • --source=SOURCE_LOCATION 标志用于指定函数源代码的位置。请参阅以下内容 了解详情:

      SOURCE_LOCATION 设置为函数源代码的位置。

    • --entry-point=CODE_ENTRYPOINT 标志指定源代码中函数的入口点。这是 函数在运行时执行的代码。您必须设置 将 CODE_ENTRYPOINT 映射到函数名称或完全限定类 名称。请参阅 函数入口点

    • --trigger-event-filters 标志定义事件过滤器,其中包括触发器类型和实体 或路径 设置以下属性值来定义事件过滤器:

      • type=EVENT_FILTER_TYPE:Firestore 支持以下事件类型:

        • google.cloud.datastore.entity.v1.created:在发生 写入实体。
        • google.cloud.datastore.entity.v1.updated:在发生 实体已存在,并且其任何值发生了更改。
        • google.cloud.datastore.entity.v1.deleted:在发生 该实体将被删除。
        • google.cloud.datastore.entity.v1.written:在发生 创建、更新或删除实体。
        • google.cloud.datastore.entity.v1.created.withAuthContext:已发送事件 当文档首次被写入且事件包含 其他身份验证信息
        • google.cloud.datastore.entity.v1.updated.withAuthContext:已发送事件 当文档已存在且其任何值发生了更改时触发。包含 其他身份验证信息
        • google.cloud.datastore.entity.v1.deleted.withAuthContext:已发送事件 在删除文档时触发。包含额外的身份验证信息
        • google.cloud.datastore.entity.v1.written.withAuthContext:已发送事件 创建、更新或删除文档时触发包含 其他身份验证信息

        EVENT_FILTER_TYPE 设置为这些事件类型之一。

      • database=DATABASE:Firestore 数据库。对于默认数据库名称,请将 DATABASE 设置为 (default)

      • namespace=NAMESPACE:数据库 命名空间。对于默认 将 NAMESPACE 设置为 (default)。移除举报 可以匹配任意命名空间

      • entity=ENTITY_OR_PATH:您要修改此参数的数据库路径 在数据被创建、更新或触发事件时触发事件 已删除。ENTITY_OR_PATH 接受的值包括:

        • 等于;例如 --trigger-event-filters="entity='users/marie'"
        • 路径模式;例如 --trigger-event-filters-path-pattern="entity='users/*'"。如需了解详情,请参阅了解路径模式

      您可以视需要在部署函数时指定其他配置网络安全选项。

      如需查看有关部署命令及其标志的完整参考信息,请参阅 gcloud functions deploy 文档。

部署示例

以下示例演示了如何使用 Google Cloud CLI 进行部署。

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

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

限制

请注意适用于 Cloud Functions 的 Firestore 触发器的以下限制:

  • Cloud Functions (第 1 代) 前提条件是 Firestore 原生模式的现有“(默认)”数据库。它不会 支持 Firestore 命名数据库或 Datastore 模式。在这种情况下,请使用 Cloud Functions (第 2 代) 来配置事件。
  • 无法保证顺序。快速更改可能会以意想不到的顺序触发函数调用。
  • 事件至少会被传送一次,但单个事件可能会导致多次调用函数。应该避免依赖“正好一次”机制,并编写幂等函数
  • Datastore 模式 Firestore 需要 Cloud Functions(第 2 代)。Cloud Functions(第 1 代)不支持 Datastore 模式。
  • 一个触发器与单一数据库相关联。您无法创建与多个数据库匹配的触发器。
  • 删除数据库不会自动删除该数据库的任何触发器。触发器会停止传送事件,但会继续存在,直到您删除触发器
  • 如果匹配的事件超过请求大小上限,该事件可能不会传送到 Cloud Functions(第 1 代)。
    • 因请求大小而未传送的事件会记录在平台日志中,并计入项目的日志使用量。
    • 您可以在 Logs Explorer 中找到这些日志,其严重性为 error 且内容为“由于大小超出第 1 代的限制,因此事件无法传送到 Cloud Functions 函数”消息。您可以在 functionName 字段下方找到函数名称。如果 receiveTimestamp 字段仍在从现在起的一小时内,您可以利用该时间戳之前和之后的快照来读取相关文档,从而推断实际事件内容。
    • 为避免这种情况发生,您可以:
      • 迁移和升级到 Cloud Functions (第 2 代)
      • 缩小文档
      • 删除相关的 Cloud Functions 函数
    • 您可以使用排除功能关闭日志记录功能本身,但请注意,违规事件仍然不会传送。

Eventarc 和 Datastore 模式 Firestore 的位置

Eventarc 不支持 Firestore 事件的多区域 触发器,但您仍然可以为 Firestore 数据库创建触发器 多区域位置Eventarc 映射 Firestore 多区域位置复制到以下 Eventarc 区域:

Firestore 多区域 Eventarc 区域
nam5 us-central1
eur3 europe-west4

后续步骤