使用 Cloud Functions (第 2 代) 擴充 Datastore

您可以使用 Cloud Run 函式和 Eventarc,部署程式碼來處理因 Firestore (Datastore 模式) 資料庫變更而觸發的事件。這樣一來,您不必執行自己的伺服器,就能新增伺服器端功能。

Datastore 模式觸發條件

Eventarc 支援下列 Firestore (Datastore 模式) 事件觸發程序,可讓您建立與 Firestore (Datastore 模式) 事件相關聯的 Cloud Run 函式 (第 2 代) 處理常式:

事件類型 觸發條件
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,資料庫可能包含非 UTF-8 編碼的舊版 ID。您必須使用 __bytesBASE64_ENCODING__ 逸出這些 ID。 將 BASE64_ENCODING 替換為 ID 的 Base64 編碼。舉例來說,路徑模式 Task/{task} (非 UTF8 類別 ID 的逸出字元為 Task) 會變成 __bytesVGFzaw==__/{task}

函式範例

下列範例示範如何接收 Datastore 模式事件。如要使用事件中的資料,請查看 valueold_value 欄位。

  • value:包含作業後實體快照的 EntityResult 物件。刪除事件不會填入這個欄位。
  • old_value:包含前置作業實體快照的 EntityResult 物件。這個欄位只會填入更新和刪除事件。

Java

如要瞭解如何安裝及使用 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:

依附元件使用相同的目錄結構。例如,將 struct.proto 放在 google/protobuf 內。

解碼事件資料時需要這些檔案。如果函式來源不含這些檔案,執行時會傳回錯誤。

活動屬性

每個事件都包含資料屬性,內含事件相關資訊,例如事件觸發時間。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 函式開發人員」IAM 角色,或包含相同權限的角色。另請參閱部署作業的其他設定

您可以使用 gcloud CLI 或 Google Cloud 控制台部署函式。以下範例說明如何使用 gcloud CLI 進行部署。如要瞭解如何使用 Google Cloud 控制台部署,請參閱部署 Cloud Run 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 Run functions (第 2 代)。如果省略這個旗標,系統會將函式部署至 Cloud Run 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 Run 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 Run 函式的 Firestore 觸發條件有下列限制:

  • 如要使用 Cloud Run 函式 (第 1 代),必須先在 Firestore 原生模式中建立「(default)」資料庫。不支援 Firestore 已命名的資料庫或 Datastore 模式。在這種情況下,請使用 Cloud Run functions (第 2 代) 設定事件。
  • 我們不保證排序。快速變更可能會以非預期的順序觸發函式呼叫。
  • 系統至少會傳送一次事件,但單一事件可能會導致多次函式叫用。請避免依附於「只執行一次」機制,並編寫等冪函式
  • Firestore (Datastore 模式) 需要 Cloud Run 函式 (第 2 代)。Cloud Run 函式 (第 1 代) 不支援 Datastore 模式。
  • 觸發條件會與單一資料庫建立關聯。您無法建立與多個資料庫相符的觸發程序。
  • 刪除資料庫時,系統不會自動刪除該資料庫的任何觸發程序。觸發條件會停止傳送事件,但會繼續存在,直到您刪除觸發條件為止。
  • 如果相符事件超過要求大小上限,事件可能無法傳送至 Cloud Run 函式 (第 1 代)。
    • 如果事件因要求大小而未傳送,系統會記錄在平台記錄中, 並計入專案的記錄檔用量。
    • 您可以在記錄檔探索器中找到這些記錄,訊息為「Event cannot deliver to Cloud function due to size exceeding the limit for 1st gen...」(事件無法傳送至 Cloud 函式,因為大小超出第 1 代的限制...),嚴重程度為 error。您可以在「functionName」欄位下方找到函式名稱。如果 receiveTimestamp 欄位仍在一小時內,您可以讀取時間戳記前後的快照,推斷實際活動內容。
    • 如要避免這種情況,可以採取下列做法:
      • 遷移及升級至 Cloud Run functions (第 2 代)
      • 縮小文件
      • 刪除有問題的 Cloud Run 函式
    • 您可以使用排除條件關閉記錄功能,但請注意,違規事件仍不會傳送。

Eventarc 和 Firestore (Datastore 模式) 位置

Eventarc 不支援 Firestore 事件觸發程序的多區域設定,但您仍可為多區域位置的 Firestore 資料庫建立觸發程序。Eventarc 會將 Firestore 多區域位置對應至下列 Eventarc 區域:

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

後續步驟