Cloud Functions(2세대)로 Datastore 확장

Cloud Functions 및 Eventarc를 사용하면 Datastore 모드의 Firestore 데이터베이스 변경으로 트리거되는 이벤트를 처리하는 코드를 배포할 수 있습니다. 이렇게 하면 자체 서버를 실행하지 않고도 서버 측 기능을 추가할 수 있습니다.

Datastore 모드 트리거

Eventarc는 Datastore 모드의 Firestore 이벤트에 연결된 Cloud Functions(2세대) 핸들러를 만들 수 있도록 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 created, updated 또는 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 모드 항목 업데이트(노옵스(no-ops) 쓰기)는 업데이트 또는 쓰기 이벤트를 생성하지 않습니다. 특정 속성에 대해서만 이벤트를 생성할 수 없습니다.

이벤트에 인증 컨텍스트 포함

이벤트에 대한 추가 인증 정보를 포함하려면 withAuthContext 확장 프로그램과 함께 이벤트 트리거를 사용합니다. 이 확장 프로그램은 이벤트를 트리거한 주 구성원에 대한 추가 정보를 추가합니다. 기본 이벤트에 반환되는 정보 외에도 authtypeauthid 속성을 추가합니다. 속성 값에 대한 자세한 내용은 authcontext 참조를 확인하세요.

항목 트리거 함수 작성

Datastore 모드의 Firestore 이벤트에 응답하는 함수를 작성하려면 배포 중에 다음을 지정할 수 있도록 준비합니다.

  • 트리거 이벤트 유형
  • 함수와 연관된 항목을 선택하는 트리거 이벤트 필터
  • 실행할 함수 코드

트리거 이벤트 필터

이벤트 필터를 지정할 때 정확한 항목 일치 또는 경로 패턴을 지정할 수 있습니다. 경로 패턴을 사용하여 와일드 카드 * 또는 **와 여러 항목을 일치시킵니다.

예를 들어 다음 항목의 변경에 응답하도록 정확한 항목 일치를 지정할 수 있습니다.

users/marie

와일드 카드(* 또는 **)를 사용하여 패턴과 일치하는 항목의 변경사항에 응답합니다. 와일드 카드 *는 단일 세그먼트와 일치하고, 다중 세그먼트 와일드 카드 **는 패턴의 0개 이상의 세그먼트와 일치합니다.

단일 세그먼트 일치(*)의 경우 이름이 지정된 캡처 그룹(예: users/{userId})을 사용할 수도 있습니다.

다음 표는 유효한 경로 패턴을 보여줍니다.

패턴 설명
users/* 또는 users/{userId} users 종류의 모든 항목과 일치합니다. /users/marie/messages/33e2IxYBD9enzS50SJ68과 같은 하위 항목 수준과 일치하지 않습니다.
users/** users 종류의 모든 항목 및 /users/marie/messages/33e2IxYBD9enzS50SJ68과 같은 모든 하위 항목과 일치합니다.

경로 패턴에 대한 자세한 내용은 Eventarc 경로 패턴을 참조하세요.

와일드 카드를 사용할 때도 트리거는 항상 항목을 가리켜야 합니다. 다음 예를 참조하세요.

  • users/{userId=*}/{messages=*}는 종류 ID이므로 {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 모드 이벤트를 수신하는 방법을 보여줍니다. 이벤트와 관련된 데이터 작업을 하려면 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.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 플래그는 함수를 배포할 리전을 지정합니다.

      근접성을 극대화하려면 FUNCTION_LOCATION을 Firestore 데이터베이스와 가까운 리전으로 설정합니다. Firestore 데이터베이스가 멀티 리전 위치에 있는 경우 값을 nam5의 데이터베이스에 대해 us-central1로 설정하고 eur3의 데이터베이스에 대해 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 트리거의 다음 제한사항에 유의하세요.

  • 순서는 보장되지 않습니다. 급격하게 변경하면 예기치 않은 순서로 함수 호출이 트리거될 수 있습니다.
  • 이벤트는 최소 1회 전송되지만 하나의 이벤트에 함수가 여러 번 호출될 수 있습니다. 정확히 한 번에 처리하는 메커니즘에 의존하지 말고 멱등 함수를 작성하세요.
  • Datastore 모드의 Cloud Firestore에는 Cloud Functions(2세대)가 필요합니다. Cloud Functions(1세대)는 Datastore 모드를 지원하지 않습니다.
  • Cloud Functions(1세대)는 '(기본값)' 데이터베이스에서만 작동하며 이름이 지정된 Firestore 데이터베이스를 지원하지 않습니다. Cloud Functions(2세대)를 사용하여 이름이 지정된 데이터베이스의 이벤트를 구성하세요.
  • 트리거는 단일 데이터베이스와 연결됩니다. 여러 데이터베이스와 일치하는 트리거를 만들 수 없습니다.
  • 데이터베이스를 삭제해도 해당 데이터베이스의 트리거가 자동으로 삭제되지 않습니다. 트리거가 이벤트 제공을 중지하지만 트리거를 삭제하기 전까지 계속 존재합니다.
  • 일치하는 이벤트가 최대 요청 크기를 초과하면 이벤트가 Cloud Functions(1세대)로 전달되지 않을 수 있습니다.
    • 요청 크기로 인해 전달되지 않은 이벤트는 플랫폼 로그에 로깅되고 프로젝트의 로그 사용량에 포함됩니다.
    • 이러한 로그는 로그 탐색기에서 '크기가 1세대... 한도를 초과하여 Cloud 함수에 이벤트를 전송할 수 없음'이라는 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

다음 단계