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

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

Datastore モードのトリガー

Eventarc は、次の Datastore モードの Firestore イベント トリガーをサポートしており、Datastore モードの Firestore イベントに関連付けられた Cloud 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 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

パターンに一致するエンティティの変更に応答するには、ワイルドカード * または ** を使用します。* ワイルドカードは 1 つのセグメントに一致し、** マルチセグメント ワイルドカードはパターン内の 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 が文字列値ではなく数値の場合は、__idNUMERIC_VALUE__ で ID をエスケープする必要があります。たとえば、種類が 111 でエンティティ ID が 222 のエンティティへのパスパターンは __id111__/__id222__ です。

  • 以前の Cloud Datastore から Datastore モードの Firestore に移行した場合、データベースに UTF8 以外のエンコードのレガシー ID が含まれる可能性があります。これらの ID は __bytesBASE64_ENCODING__ でエスケープする必要があります。BASE64_ENCODING は、ID の base-64 エンコードに置き換えます。たとえば、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 Functions の関数をデプロイするユーザーには、Cloud Functions デベロッパーの IAM ロールまたは同等の権限を含むロールが必要です。デプロイの追加構成もご覧ください。

関数をデプロイするには、gcloud CLI または Google Cloud コンソールを使用します。以下の例は、gcloud CLI を使用したデプロイを示しています。Google Cloud コンソールを使用したデプロイの詳細については、Cloud Functions のデプロイをご覧ください。

  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 Functions(第 2 世代)にデプロイすることを指定します。このフラグを省略すると、Cloud Functions(第 1 世代)にデプロイされます。

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

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

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

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

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

次のステップ