Cloud Functions(第 2 世代)を使用して Datastore を拡張する

Cloud Run functions と Eventarc を使用すると、Datastore モードの Firestore データベースの変更によってトリガーされるイベントを処理するコードをデプロイできます。これにより、独自のサーバーを実行しなくても、サーバー側の機能を追加できます。

Datastore モードのトリガー

Eventarc は、Datastore モードの Firestore イベント トリガーをサポートしています。これにより、Datastore モードの Firestore イベントに関連付けられた 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 createdupdated または deleted がトリガーされたときにトリガーされます。
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 拡張機能とともにイベント トリガーを使用します。この拡張機能は、イベントをトリガーしたプリンシパルに関する追加情報を追加します。ベースイベントで返される情報に加えて、authtype 属性と authid 属性を追加します。属性値の詳細については、authcontext のリファレンスをご覧ください。

エンティティでトリガーされる関数を作成する

Datastore モードの Firestore のイベントに応答する関数を作成するには、デプロイ中に次の内容を指定する準備を行います。

  • トリガー イベントのタイプ
  • 関数に関連付けられたエンティティを選択するトリガー イベント フィルタ
  • 実行する関数コード

トリガー イベント フィルタ

イベント フィルタを指定するときに、エンティティの完全一致またはパスパターンを指定できます。パスパターンを使用して、ワイルドカード * または ** を使用して複数のエンティティに一致させます。

たとえば、次のエンティティの変更に応答するように、エンティティの完全一致を指定できます。

users/marie

パターンに一致するエンティティの変更に対応するには、ワイルドカード * または ** を使用します。* ワイルドカードは単一のセグメントに一致し、** マルチセグメント ワイルドカードはパターン内の 0 個以上のセグメントに一致します。

単一セグメントの一致(*)の場合は、users/{userId} などの名前付きキャプチャ グループを使用することもできます。

次の表に、有効なパスパターンを示します。

パターン 説明
users/* または users/{userId} 種類 users のすべてのエンティティを照合します。/users/marie/messages/33e2IxYBD9enzS50SJ68 のような子孫エンティティ レベルは照合しません。
users/** 種類 users のすべてのエンティティと、/users/marie/messages/33e2IxYBD9enzS50SJ68 などのすべての子孫エンティティに一致します。

パスパターンの詳細については、Eventarc パスのパターンをご覧ください。

ワイルドカードを使用する場合でも、トリガーは常にエンティティを指している必要があります。次の例をご覧ください。

  • {messages=*} は種類 ID であるため、users/{userId=*}/{messages=*} は無効です。

  • {messageId=*} は常にエンティティを指すため、users/{userId=*}/{messages}/{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 またはエンティティ ID が文字列値ではなく数値値の場合は、__idNUMERIC_VALUE__ で ID をエスケープする必要があります。たとえば、種類が 111 でエンティティ ID が 222 のエンティティのパスパターンは __id111__/__id222__ です。

  • 以前の Cloud Datastore から Datastore モードの Firestore に移行した場合、データベースに UTF8 以外のエンコードの以前の ID が含まれている可能性があります。これらの ID は __bytesBASE64_ENCODING__ でエスケープする必要があります。BASE64_ENCODING は、ID の Base64 エンコードに置き換えます。たとえば、UTF8 以外の種類 ID Task のエスケープを含むパスパターン Task/{task} は、__bytesVGFzaw==__/{task} になります。

関数の例

次の例では、Datastore モードのイベントを受信する方法を示しています。イベントに関連するデータを操作するには、value フィールドと old_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.protogoogle/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 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 関数(第 2 世代)にデプロイすることを指定します。このフラグを省略すると、Cloud Run 関数(第 1 世代)にデプロイされます。

    • --region=FUNCTION_LOCATION フラグには、関数をデプロイするリージョンを指定します。

      近接性を最大化するには、Firestore データベースの近くのリージョンに FUNCTION_LOCATION を設定します。Firestore データベースがマルチリージョン ロケーションにある場合、nam5 のデータベースの場合は us-central1 に、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 関数(第 2 世代)を使用してください。
  • 順序は保証されません。短時間に複数の変更を行うと、予期しない順序で関数の呼び出しがトリガーされることがあります。
  • イベントは必ず 1 回以上処理されますが、1 つのイベントで関数が複数回呼び出される場合があります。「正確に 1 回」のメカニズムに依存することは避け、べき等性がある関数を記述してください。
  • Datastore モードの Firestore には、Cloud Run 関数(第 2 世代)が必要です。Cloud Run 関数(第 1 世代)では、Datastore モードはサポートされていません。
  • トリガーは、単一のデータベースに関連付けられます。複数のデータベースに一致するトリガーは作成できません。
  • データベースを削除しても、そのデータベースのトリガーは自動的に削除されません。トリガーはイベントの配信を停止しますが、トリガーを削除するまで存在し続けます。
  • 一致したイベントが最大リクエスト サイズを超えると、Cloud Run functions(第 1 世代)に配信されない可能性があります。
    • リクエスト サイズが原因で配信されなかったイベントは、プラットフォーム ログに記録され、プロジェクトのログ使用量にカウントされます。
    • これらのログは、ログ エクスプローラで「サイズが第 1 世代の上限を超えているため、イベントを Cloud Functions に配信できません...」という error 重大度メッセージとともに表示されます。関数名は functionName フィールドで確認できます。receiveTimestamp フィールドが現在から 1 時間以内であれば、タイムスタンプの前後のスナップショットで問題のドキュメントを読み取ることで、実際のイベントの内容を推測できます。
    • このようなケイデンスを回避するには、次のようにします。
      • Cloud Run 関数(第 2 世代)に移行してアップグレードする
      • ドキュメントのサイズを縮小する
      • 問題の Cloud Run 関数を削除する
    • 除外を使用してロギング自体を無効にすることもできますが、問題のあるイベントは引き続き配信されないことに注意してください。

Eventarc と Datastore モードの Firestore のロケーション

Eventarc は、Firestore イベント トリガーのマルチリージョンをサポートしていませんが、マルチリージョン ロケーションの Firestore データベースのトリガーは作成できます。Eventarc は、Firestore マルチリージョン ロケーションを次の Eventarc リージョンにマッピングします。

Firestore マルチリージョン Eventarc リージョン
nam5 us-central1
eur3 europe-west4

次のステップ