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

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

Datastore 模式觸發條件

Eventarc 支援下列 Datastore 模式下的 Firestore 事件觸發條件,可讓您建立與 Datastore 模式下的 Firestore 事件相關聯的 Cloud Run functions (第 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 完全是 ... 時,才需要逸出 . 字元。 舉例來說,kind 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 模式用戶端程式庫」。詳情請參閱 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 functions 時,必須具備 Cloud Run 函式開發人員 IAM 或包含相同權限的角色。另請參閱部署作業的其他設定

您可以使用 gcloud CLI 或 Google Cloud 控制台部署函式。以下範例說明如何使用 gcloud CLI 進行部署。如要瞭解如何使用 Google Cloud 控制台部署,請參閱「部署 Cloud Run 函式」。

  1. 在 Google Cloud 控制台中啟用 Cloud Shell。

    啟用 Cloud Shell

    Google Cloud 主控台底部會開啟一個 Cloud Shell 工作階段,並顯示指令列提示。Cloud Shell 是已安裝 Google Cloud CLI 的殼層環境,並已針對您目前的專案設定好相關值。工作階段可能要幾秒鐘的時間才能初始化。

  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。包括其他驗證資訊

        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 functions 的 Firestore 觸發條件有下列限制:

  • Cloud Run functions (第 1 代) 僅支援 Firestore 原生模式下既有的「(default)」資料庫,不支援 Firestore 的具名資料庫或 Datastore 模式,在後者的情況下,請改用 Cloud Run functions (第 2 代) 設定事件。
  • 目前不支援跨專案設定 Cloud Run functions 和 Firestore 觸發條件。如要設定 Firestore 觸發條件,Cloud Run functions 必須位於同一個專案中。
  • 函式的叫用並無一定順序。在快速變更的情形下,可能會以非預期的順序觸發函式叫用。
  • 事件至少會傳送一次,但單一事件可能會導致多次函式叫用。請避免依賴「恰好一次」的機制,並務必編寫冪等函式
  • Datastore 模式下的 Firestore 需要 Cloud Run functions (第 2 代)。Cloud Run functions (第 1 代) 不支援 Datastore 模式。
  • 每項觸發條件僅能關聯至單一資料庫,無法建立同時比對多個資料庫的觸發條件。
  • 刪除資料庫時,相關觸發條件並不自動隨之刪除,僅會停止傳送事件,並持續保留到手動刪除為止。
  • 如果比對符合事件超過要求大小上限,事件可能無法傳送至 Cloud Run functions (第 1 代)。
    • 如果事件因要求大小而未能傳送,這些事件會記錄於平台記錄檔,並計入專案的記錄用量。
    • 這些記錄位於 Logs Explorer 中,訊息為「Event cannot deliver to Cloud function due to size exceeding the limit for 1st gen...」(因事件大小超出第一代限制,無法傳遞至 Cloud 函式),嚴重程度為 error。函式名稱位於 functionName 欄位下方。如果 receiveTimestamp 欄位的時間戳記仍在一小時內,則可讀取該時間點前後的相關文件快照,推斷實際的事件內容。
    • 如要避免此情況,建議方法如下:
      • 遷移並升級至 Cloud Run functions (第 2 代)
      • 縮減文件大小
      • 刪除受影響的 Cloud Run functions
    • 您可以使用排除條件關閉記錄功能,但請注意,超出限制的事件仍不會傳送。

Eventarc 和 Firestore (Datastore 模式) 位置

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

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

後續步驟