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

借助 Cloud Run 函数和 Eventarc,您可以部署代码来处理因 Datastore 模式 Firestore 数据库更改而触发的事件。这样您就可以添加服务器端功能,而无需运行自己的服务器。

Datastore 模式触发器

Eventarc 支持以下 Datastore 模式 Firestore 事件 触发器,让您可以创建 Cloud Run 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 文件(位于函数源目录中)。此文件会导入以下 proto,您也必须将其添加到源目录中:

为依赖项使用相同的目录结构。例如,地点 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 Run 函数的用户必须拥有 Cloud Run Functions 开发者 IAM 角色或包含相同权限的角色。另请参阅其他部署配置

您可以使用 gcloud CLI 部署函数 或 Google Cloud 控制台以下示例演示了如何使用 gcloud CLI如需详细了解如何使用 Google Cloud 控制台进行部署,请参阅部署 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. 使用 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 Run functions(第 2 代)。省略 此标志会导致部署到 Cloud Run 函数(第 1 代)。

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

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

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

    • --runtime=RUNTIME 标志指定函数使用的语言运行时。Cloud Run 函数支持多种运行时。请参阅 运行时。 将 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。对于默认数据库名称,请将 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 Run 函数的 Firestore 触发器,请注意以下限制:

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

Datastore 模式 Eventarc 和 Firestore 的位置

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

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

后续步骤