Acione funções com documentos do Firestore

Este guia mostra exemplos de funções que são acionadas quando faz alterações a um documento numa coleção especificada.

Antes de começar

Antes de executar o código de exemplo neste guia, tem de fazer o seguinte:

Exemplos

Os exemplos seguintes demonstram como escrever funções que respondem a um acionador do Firestore.

Exemplo 1: função Hello Firestore

O exemplo seguinte imprime os campos de um evento do Firestore de acionamento:

Node.js

/**
 * Cloud Event Function triggered by a change to a Firestore document.
 */
const functions = require('@google-cloud/functions-framework');
const protobuf = require('protobufjs');

functions.cloudEvent('helloFirestore', async cloudEvent => {
  console.log(`Function triggered by event on: ${cloudEvent.source}`);
  console.log(`Event type: ${cloudEvent.type}`);

  console.log('Loading protos...');
  const root = await protobuf.load('data.proto');
  const DocumentEventData = root.lookupType(
    'google.events.cloud.firestore.v1.DocumentEventData'
  );

  console.log('Decoding data...');
  const firestoreReceived = DocumentEventData.decode(cloudEvent.data);

  console.log('\nOld value:');
  console.log(JSON.stringify(firestoreReceived.oldValue, null, 2));

  console.log('\nNew value:');
  console.log(JSON.stringify(firestoreReceived.value, null, 2));
});

Python

from cloudevents.http import CloudEvent
import functions_framework
from google.events.cloud import firestore


@functions_framework.cloud_event
def hello_firestore(cloud_event: CloudEvent) -> None:
    """Triggers by a change to a Firestore document.

    Args:
        cloud_event: cloud event with information on the firestore event trigger
    """
    firestore_payload = firestore.DocumentEventData()
    firestore_payload._pb.ParseFromString(cloud_event.data)

    print(f"Function triggered by change to: {cloud_event['source']}")

    print("\nOld value:")
    print(firestore_payload.old_value)

    print("\nNew value:")
    print(firestore_payload.value)

Ir


// Package hellofirestore contains a Cloud Event Function triggered by a Cloud Firestore event.
package hellofirestore

import (
	"context"
	"fmt"

	"github.com/GoogleCloudPlatform/functions-framework-go/functions"
	"github.com/cloudevents/sdk-go/v2/event"
	"github.com/googleapis/google-cloudevents-go/cloud/firestoredata"
	"google.golang.org/protobuf/proto"
)

func init() {
	functions.CloudEvent("helloFirestore", HelloFirestore)
}

// HelloFirestore is triggered by a change to a Firestore document.
func HelloFirestore(ctx context.Context, event event.Event) error {
	var data firestoredata.DocumentEventData

	// If you omit `DiscardUnknown`, protojson.Unmarshal returns an error
	// when encountering a new or unknown field.
	options := proto.UnmarshalOptions{
		DiscardUnknown: true,
	}
	err := options.Unmarshal(event.Data(), &data)

	if err != nil {
		return fmt.Errorf("proto.Unmarshal: %w", err)
	}

	fmt.Printf("Function triggered by change to: %v\n", event.Source())
	fmt.Printf("Old value: %+v\n", data.GetOldValue())
	fmt.Printf("New value: %+v\n", data.GetValue())
	return nil
}

Java

import com.google.cloud.functions.CloudEventsFunction;
import com.google.events.cloud.firestore.v1.DocumentEventData;
import com.google.protobuf.InvalidProtocolBufferException;
import io.cloudevents.CloudEvent;
import java.util.logging.Logger;

public class FirebaseFirestore implements CloudEventsFunction {
  private static final Logger logger = Logger.getLogger(FirebaseFirestore.class.getName());

  @Override
  public void accept(CloudEvent event) throws InvalidProtocolBufferException {
    DocumentEventData firestoreEventData = DocumentEventData
        .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(firestoreEventData.getOldValue().toString());

    logger.info("New value:");
    logger.info(firestoreEventData.getValue().toString());
  }
}

C#

using CloudNative.CloudEvents;
using Google.Cloud.Functions.Framework;
using Google.Events.Protobuf.Cloud.Firestore.V1;
using Microsoft.Extensions.Logging;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace FirebaseFirestore;

public class Function : ICloudEventFunction<DocumentEventData>
{
    private readonly ILogger _logger;

    public Function(ILogger<Function> logger) =>
        _logger = logger;

    public Task HandleAsync(CloudEvent cloudEvent, DocumentEventData data, CancellationToken cancellationToken)
    {
        _logger.LogInformation("Function triggered by event on {subject}", cloudEvent.Subject);
        _logger.LogInformation("Event type: {type}", cloudEvent.Type);
        MaybeLogDocument("Old value", data.OldValue);
        MaybeLogDocument("New value", data.Value);

        // In this example, we don't need to perform any asynchronous operations, so the
        // method doesn't need to be declared async.
        return Task.CompletedTask;
    }

    /// <summary>
    /// Logs the names and values of the fields in a document in a very simplistic way.
    /// </summary>
    private void MaybeLogDocument(string message, Document document)
    {
        if (document is null)
        {
            return;
        }

        // ConvertFields converts the Firestore representation into a .NET-friendly
        // representation.
        IReadOnlyDictionary<string, object> fields = document.ConvertFields();
        var fieldNamesAndTypes = fields
            .OrderBy(pair => pair.Key)
            .Select(pair => $"{pair.Key}: {pair.Value}");
        _logger.LogInformation(message + ": {fields}", string.Join(", ", fieldNamesAndTypes));
    }
}

Implemente a função Hello Firestore

Se ainda não o fez, configure a sua base de dados do Firestore.

Clique no separador para ver instruções sobre como usar a ferramenta da sua escolha.

Consola

Quando usa a Google Cloud consola para criar uma função, também pode adicionar um acionador à sua função. Siga estes passos para criar um acionador para a sua função:

  1. Na Google Cloud consola, aceda ao Cloud Run:

    Aceda ao Cloud Run

  2. Clique em Escrever uma função e introduza os detalhes da função. Para mais informações sobre a configuração de funções durante a implementação, consulte Implementar funções.

  3. Na secção Acionador, clique em Adicionar acionador.

  4. Selecione Acionador do Firestore.

  5. No painel Acionador do Eventarc, modifique os detalhes do acionador da seguinte forma:

    1. Introduza um nome para o acionador no campo Nome do acionador ou use o nome predefinido.

    2. Selecione um Tipo de acionador na lista:

      • Origens Google para especificar acionadores para o Pub/Sub, o Cloud Storage, o Firestore e outros fornecedores de eventos Google.

      • Terceiros para integrar com fornecedores que não sejam da Google que oferecem uma origem do Eventarc. Para mais informações, consulte o artigo Eventos de terceiros no Eventarc.

    3. Selecione Firestore na lista Fornecedor de eventos para selecionar um produto que forneça o tipo de evento para acionar a sua função. Para ver a lista de fornecedores de eventos, consulte o artigo Fornecedores de eventos e destinos.

    4. Selecione type=google.cloud.firestore.document.v1.written na lista Tipo de evento. A configuração do acionador varia consoante o tipo de evento suportado. Para mais informações, consulte o artigo Tipos de eventos.

    5. Na secção Filtros, selecione uma base de dados, uma operação e valores de atributos, ou use as seleções predefinidas.

    6. Se o campo Região estiver ativado, selecione uma localização para o acionador do Eventarc. Em geral, a localização de um acionador do Eventarc deve corresponder à localização do recurso que quer monitorizar para eventos. Google Cloud Na maioria dos cenários, também deve implementar a função na mesma região. Consulte o artigo Compreenda as localizações do Eventarc para ver mais detalhes sobre as localizações dos acionadores do Eventarc.

    7. No campo Conta de serviço, selecione uma conta de serviço. Os acionadores do Eventarc estão associados a contas de serviço para usar como identidade quando invocam a sua função. A conta de serviço do acionador do Eventarc tem de ter a autorização para invocar a sua função. Por predefinição, o Cloud Run usa a conta de serviço predefinida do Compute Engine.

    8. Opcionalmente, especifique o caminho do URL do serviço para o qual enviar o pedido recebido. Este é o caminho relativo no serviço de destino para o qual os eventos do acionador devem ser enviados. Por exemplo: /, /route, route e route/subroute.

  6. Depois de preencher os campos obrigatórios, clique em Guardar acionador.

gcloud

Quando cria uma função através da CLI gcloud, tem primeiro de implementar a função e, em seguida, criar um acionador. Siga estes passos para criar um acionador para a sua função:

  1. Execute o seguinte comando no diretório que contém o código de exemplo para implementar a sua função:

    gcloud run deploy FUNCTION \
            --source . \
            --function FUNCTION_ENTRYPOINT \
            --base-image BASE_IMAGE_ID \
            --region REGION
    

    Substituir:

    • FUNCTION com o nome da função que está a implementar. Pode omitir este parâmetro por completo, mas é-lhe pedido o nome se o omitir.

    • FUNCTION_ENTRYPOINT com o ponto de entrada da sua função no código-fonte. Este é o código que o Cloud Run executa quando a sua função é executada. O valor desta flag tem de ser um nome de função ou um nome de classe totalmente qualificado que exista no seu código-fonte.

    • BASE_IMAGE_ID com o ambiente de imagem base para a sua função. Para mais detalhes sobre as imagens base e os pacotes incluídos em cada imagem, consulte o artigo Imagens base de tempos de execução.

    • REGION com a Google Cloud região onde quer implementar a sua função. Por exemplo, europe-west1.

  2. Execute o seguinte comando para criar um acionador que filtra eventos:

    gcloud eventarc triggers create TRIGGER_NAME  \
        --location=EVENTARC_TRIGGER_LOCATION \
        --destination-run-service=FUNCTION  \
        --destination-run-region=REGION \
        --event-filters=type=google.cloud.firestore.document.v1.written \
        --event-filters=database='(default)' \
        --event-data-content-type=application/protobuf \
        --event-filters-path-pattern=document='users/{username}' \
        --service-account=PROJECT_NUMBER-compute@developer.gserviceaccount.com
    

    Substituir:

    • TRIGGER_NAME com o nome do acionador.

    • EVENTARC_TRIGGER_LOCATION com a localização do acionador do Eventarc. Em geral, a localização de um acionador do Eventarc deve corresponder à localização do Google Cloud recurso que quer monitorizar para eventos. Na maioria dos cenários, também deve implementar a função na mesma região. Para mais informações, consulte o artigo Localizações do Eventarc.

    • FUNCTION com o nome da função que está a implementar.

    • REGION com a região do Cloud Run da função.

    • PROJECT_NUMBER com o seu Google Cloud número do projeto. Os acionadores do Eventarc estão associados a contas de serviço para serem usados como uma identidade quando invocam a sua função. A conta de serviço do seu acionador do Eventarc tem de ter autorização para invocar a sua função. Por predefinição, o Cloud Run usa a conta de serviço de computação predefinida.

    Cada sinalização event-filters especifica um tipo de evento, com a função a ser acionada apenas quando um evento cumpre todos os critérios especificados nas respetivas sinalizações event-filters. Cada acionador tem de ter uma flag event-filters que especifique um tipo de evento suportado, como um novo documento escrito no Firestore ou um ficheiro carregado para o Cloud Storage. Não pode alterar o tipo de filtro de eventos após a criação. Para alterar o tipo de filtro de eventos, tem de criar um novo acionador e eliminar o antigo. Opcionalmente, pode repetir a flag --event-filters com um filtro suportado no formato ATTRIBUTE=VALUE para adicionar mais filtros.

Terraform

Para criar um acionador do Eventarc para uma função do Cloud Run, consulte o artigo Crie um acionador com o Terraform.

Use os outros campos tal como estão:

  • --event-filters=type=google.cloud.firestore.document.v1.written especifica que a função é acionada quando um documento é criado, atualizado ou eliminado, de acordo com o google.cloud.firestore.document.v1.written tipo de evento.
  • --event-filters=database='(default)' especifica a base de dados do Firebase. Para o nome da base de dados predefinido, use (default).
  • --event-filters-path-pattern=document='users/{username}' fornece o padrão do caminho dos documentos que devem ser monitorizados para alterações relevantes. Este padrão de caminho indica que todos os documentos na coleção users devem ser monitorizados. Para mais informações, consulte o artigo Compreenda os padrões de caminhos.

Teste a função Hello Firestore

Para testar a função Hello Firestore, configure uma coleção denominada users na sua base de dados do Firestore:

  1. Na Google Cloud consola, aceda à página de bases de dados do Firestore:

    Aceder ao Firestore

  2. Clique em Iniciar uma coleção.

  3. Especifique users como o ID da coleção.

  4. Para começar a adicionar o primeiro documento da coleção, em Adicionar o primeiro documento, aceite o ID do documento gerado automaticamente.

  5. Adicione, pelo menos, um campo para o documento, especificando um nome e um valor. Por exemplo, em Nome do campo, introduza username e, em Valor do campo, introduza rowan.

  6. Quando terminar, clique em Guardar.

    Esta ação cria um novo documento, acionando assim a sua função.

  7. Para confirmar que a sua função foi acionada, clique no nome associado da função na Google Cloud consola página Vista geral do Cloud Run para abrir a página Detalhes do serviço.

  8. Selecione o separador Registos e procure esta string:

Function triggered by change to: //firestore.googleapis.com/projects/your-project-id/databases/(default)'

Exemplo 2: função de conversão em maiúsculas

O exemplo seguinte obtém o valor adicionado pelo utilizador, converte a string nessa localização em letras maiúsculas e substitui o valor pela string em letras maiúsculas:

Node.js

Use protobufjs para descodificar os dados do evento. Inclua o google.events.cloud.firestore.v1 data.proto na sua fonte.

const functions = require('@google-cloud/functions-framework');
const Firestore = require('@google-cloud/firestore');
const protobuf = require('protobufjs');

const firestore = new Firestore({
  projectId: process.env.GOOGLE_CLOUD_PROJECT,
});

// Converts strings added to /messages/{pushId}/original to uppercase
functions.cloudEvent('makeUpperCase', async cloudEvent => {
  console.log('Loading protos...');
  const root = await protobuf.load('data.proto');
  const DocumentEventData = root.lookupType(
    'google.events.cloud.firestore.v1.DocumentEventData'
  );

  console.log('Decoding data...');
  const firestoreReceived = DocumentEventData.decode(cloudEvent.data);

  const resource = firestoreReceived.value.name;
  const affectedDoc = firestore.doc(resource.split('/documents/')[1]);

  const curValue = firestoreReceived.value.fields.original.stringValue;
  const newValue = curValue.toUpperCase();

  if (curValue === newValue) {
    // Value is already upper-case
    // Don't perform a(nother) write to avoid infinite loops
    console.log('Value is already upper-case.');
    return;
  }

  console.log(`Replacing value: ${curValue} --> ${newValue}`);
  affectedDoc.set({
    original: newValue,
  });
});

Python

from cloudevents.http import CloudEvent
import functions_framework
from google.cloud import firestore
from google.events.cloud import firestore as firestoredata

client = firestore.Client()


# Converts strings added to /messages/{pushId}/original to uppercase
@functions_framework.cloud_event
def make_upper_case(cloud_event: CloudEvent) -> None:
    firestore_payload = firestoredata.DocumentEventData()
    firestore_payload._pb.ParseFromString(cloud_event.data)

    path_parts = firestore_payload.value.name.split("/")
    separator_idx = path_parts.index("documents")
    collection_path = path_parts[separator_idx + 1]
    document_path = "/".join(path_parts[(separator_idx + 2) :])

    print(f"Collection path: {collection_path}")
    print(f"Document path: {document_path}")

    affected_doc = client.collection(collection_path).document(document_path)

    cur_value = firestore_payload.value.fields["original"].string_value
    new_value = cur_value.upper()

    if cur_value != new_value:
        print(f"Replacing value: {cur_value} --> {new_value}")
        affected_doc.set({"original": new_value})
    else:
        # Value is already upper-case
        # Don't perform a second write (which can trigger an infinite loop)
        print("Value is already upper-case.")

Ir


// Package upper contains a Firestore Cloud Function.
package upper

import (
	"context"
	"errors"
	"fmt"
	"log"
	"os"
	"strings"

	"cloud.google.com/go/firestore"
	firebase "firebase.google.com/go/v4"
	"github.com/GoogleCloudPlatform/functions-framework-go/functions"
	"github.com/cloudevents/sdk-go/v2/event"
	"github.com/googleapis/google-cloudevents-go/cloud/firestoredata"
	"google.golang.org/protobuf/proto"
)

// set the GOOGLE_CLOUD_PROJECT environment variable when deploying.
var projectID = os.Getenv("GOOGLE_CLOUD_PROJECT")

// client is a Firestore client, reused between function invocations.
var client *firestore.Client

func init() {
	// Use the application default credentials.
	conf := &firebase.Config{ProjectID: projectID}

	// Use context.Background() because the app/client should persist across
	// invocations.
	ctx := context.Background()

	app, err := firebase.NewApp(ctx, conf)
	if err != nil {
		log.Fatalf("firebase.NewApp: %v", err)
	}

	client, err = app.Firestore(ctx)
	if err != nil {
		log.Fatalf("app.Firestore: %v", err)
	}

	// Register cloud event function
	functions.CloudEvent("MakeUpperCase", MakeUpperCase)
}

// MakeUpperCase is triggered by a change to a Firestore document. It updates
// the `original` value of the document to upper case.
func MakeUpperCase(ctx context.Context, e event.Event) error {
	var data firestoredata.DocumentEventData

	// If you omit `DiscardUnknown`, protojson.Unmarshal returns an error
	// when encountering a new or unknown field.
	options := proto.UnmarshalOptions{
		DiscardUnknown: true,
	}
	err := options.Unmarshal(e.Data(), &data)

	if err != nil {
		return fmt.Errorf("proto.Unmarshal: %w", err)
	}

	if data.GetValue() == nil {
		return errors.New("Invalid message: 'Value' not present")
	}

	fullPath := strings.Split(data.GetValue().GetName(), "/documents/")[1]
	pathParts := strings.Split(fullPath, "/")
	collection := pathParts[0]
	doc := strings.Join(pathParts[1:], "/")

	var originalStringValue string
	if v, ok := data.GetValue().GetFields()["original"]; ok {
		originalStringValue = v.GetStringValue()
	} else {
		return errors.New("Document did not contain field \"original\"")
	}

	newValue := strings.ToUpper(originalStringValue)
	if originalStringValue == newValue {
		log.Printf("%q is already upper case: skipping", originalStringValue)
		return nil
	}
	log.Printf("Replacing value: %q -> %q", originalStringValue, newValue)

	newDocumentEntry := map[string]string{"original": newValue}
	_, err = client.Collection(collection).Doc(doc).Set(ctx, newDocumentEntry)
	if err != nil {
		return fmt.Errorf("Set: %w", err)
	}
	return nil
}

Java

import com.google.cloud.firestore.Firestore;
import com.google.cloud.firestore.FirestoreOptions;
import com.google.cloud.firestore.SetOptions;
import com.google.cloud.functions.CloudEventsFunction;
import com.google.events.cloud.firestore.v1.DocumentEventData;
import com.google.events.cloud.firestore.v1.Value;
import com.google.protobuf.InvalidProtocolBufferException;
import io.cloudevents.CloudEvent;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.logging.Logger;

public class FirebaseFirestoreReactive implements CloudEventsFunction {
  private static final Logger logger = Logger.getLogger(FirebaseFirestoreReactive.class.getName());
  private final Firestore firestore;

  private static final String FIELD_KEY = "original";
  private static final String APPLICATION_PROTOBUF = "application/protobuf";

  public FirebaseFirestoreReactive() {
    this(FirestoreOptions.getDefaultInstance().getService());
  }

  public FirebaseFirestoreReactive(Firestore firestore) {
    this.firestore = firestore;
  }

  @Override
  public void accept(CloudEvent event)
      throws InvalidProtocolBufferException, InterruptedException, ExecutionException {
    if (event.getData() == null) {
      logger.warning("No data found in event!");
      return;
    }

    if (!event.getDataContentType().equals(APPLICATION_PROTOBUF)) {
      logger.warning(String.format("Found unexpected content type %s, expected %s",
          event.getDataContentType(),
          APPLICATION_PROTOBUF));
      return;
    }

    DocumentEventData firestoreEventData = DocumentEventData
        .parseFrom(event.getData().toBytes());

    // Get the fields from the post-operation document snapshot
    // https://firebase.google.com/docs/firestore/reference/rest/v1/projects.databases.documents#Document
    Map<String, Value> fields = firestoreEventData.getValue().getFieldsMap();
    if (!fields.containsKey(FIELD_KEY)) {
      logger.warning("Document does not contain original field");
      return;
    }
    String currValue = fields.get(FIELD_KEY).getStringValue();
    String newValue = currValue.toUpperCase();

    if (currValue.equals(newValue)) {
      logger.info("Value is already upper-case");
      return;
    }

    // Retrieve the document name from the resource path:
    // projects/{project_id}/databases/{database_id}/documents/{document_path}
    String affectedDoc = firestoreEventData.getValue()
        .getName()
        .split("/documents/")[1]
        .replace("\"", "");

    logger.info(String.format("Replacing values: %s --> %s", currValue, newValue));

    // Wait for the async call to complete
    this.firestore
        .document(affectedDoc)
        .set(Map.of(FIELD_KEY, newValue), SetOptions.merge())
        .get();
  }
}

C#

using CloudNative.CloudEvents;
using Google.Cloud.Firestore;
using Google.Cloud.Functions.Framework;
using Google.Cloud.Functions.Hosting;
using Google.Events.Protobuf.Cloud.Firestore.V1;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace FirestoreReactive;

public class Startup : FunctionsStartup
{
    public override void ConfigureServices(WebHostBuilderContext context, IServiceCollection services) =>
        services.AddSingleton(FirestoreDb.Create());
}

// Register the startup class to provide the Firestore dependency.
[FunctionsStartup(typeof(Startup))]
public class Function : ICloudEventFunction<DocumentEventData>
{
    private readonly ILogger _logger;
    private readonly FirestoreDb _firestoreDb;

    public Function(ILogger<Function> logger, FirestoreDb firestoreDb) =>
        (_logger, _firestoreDb) = (logger, firestoreDb);

    public async Task HandleAsync(CloudEvent cloudEvent, DocumentEventData data, CancellationToken cancellationToken)
    {
        // Get the recently-written value. This expression will result in a null value
        // if any of the following is true:
        // - The event doesn't contain a "new" document
        // - The value doesn't contain a field called "original"
        // - The "original" field isn't a string
        string currentValue = data.Value?.ConvertFields().GetValueOrDefault("original") as string;
        if (currentValue is null)
        {
            _logger.LogWarning($"Event did not contain a suitable document");
            return;
        }

        string newValue = currentValue.ToUpperInvariant();
        if (newValue == currentValue)
        {
            _logger.LogInformation("Value is already upper-cased; no replacement necessary");
            return;
        }

        // The CloudEvent subject is "documents/x/y/...".
        // The Firestore SDK FirestoreDb.Document method expects a reference relative to
        // "documents" (so just the "x/y/..." part). This may be simplified over time.
        if (cloudEvent.Subject is null || !cloudEvent.Subject.StartsWith("documents/"))
        {
            _logger.LogWarning("CloudEvent subject is not a document reference.");
            return;
        }
        string documentPath = cloudEvent.Subject.Substring("documents/".Length);

        _logger.LogInformation("Replacing '{current}' with '{new}' in '{path}'", currentValue, newValue, documentPath);
        await _firestoreDb.Document(documentPath).UpdateAsync("original", newValue, cancellationToken: cancellationToken);
    }
}

Implemente a função Converter em maiúsculas

Se ainda não o fez, configure a sua base de dados do Firestore.

Clique no separador para ver instruções sobre como usar a ferramenta da sua escolha.

Consola

Quando usa a Google Cloud consola para criar uma função, também pode adicionar um acionador à sua função. Siga estes passos para criar um acionador para a sua função:

  1. Na Google Cloud consola, aceda ao Cloud Run:

    Aceda ao Cloud Run

  2. Clique em Escrever uma função e introduza os detalhes da função. Para mais informações sobre a configuração de funções durante a implementação, consulte Implementar funções.

  3. Na secção Acionador, clique em Adicionar acionador.

  4. Selecione Acionador do Firestore.

  5. No painel Acionador do Eventarc, modifique os detalhes do acionador da seguinte forma:

    1. Introduza um nome para o acionador no campo Nome do acionador ou use o nome predefinido.

    2. Selecione um Tipo de acionador na lista:

      • Origens Google para especificar acionadores para o Pub/Sub, o Cloud Storage, o Firestore e outros fornecedores de eventos Google.

      • Terceiros para integrar com fornecedores que não sejam da Google que oferecem uma origem do Eventarc. Para mais informações, consulte o artigo Eventos de terceiros no Eventarc.

    3. Selecione Firestore na lista Fornecedor de eventos para selecionar um produto que forneça o tipo de evento para acionar a sua função. Para ver a lista de fornecedores de eventos, consulte o artigo Fornecedores de eventos e destinos.

    4. Selecione type=google.cloud.firestore.document.v1.written na lista Tipo de evento. A configuração do acionador varia consoante o tipo de evento suportado. Para mais informações, consulte o artigo Tipos de eventos.

    5. Na secção Filtros, selecione uma base de dados, uma operação e valores de atributos, ou use as seleções predefinidas.

    6. Se o campo Região estiver ativado, selecione uma localização para o acionador do Eventarc. Em geral, a localização de um acionador do Eventarc deve corresponder à localização do recurso que quer monitorizar para eventos. Google Cloud Na maioria dos cenários, também deve implementar a função na mesma região. Consulte o artigo Compreenda as localizações do Eventarc para ver mais detalhes sobre as localizações dos acionadores do Eventarc.

    7. No campo Conta de serviço, selecione uma conta de serviço. Os acionadores do Eventarc estão associados a contas de serviço para usar como identidade quando invocam a sua função. A conta de serviço do acionador do Eventarc tem de ter a autorização para invocar a sua função. Por predefinição, o Cloud Run usa a conta de serviço predefinida do Compute Engine.

    8. Opcionalmente, especifique o caminho do URL do serviço para o qual enviar o pedido recebido. Este é o caminho relativo no serviço de destino para o qual os eventos do acionador devem ser enviados. Por exemplo: /, /route, route e route/subroute.

  6. Depois de preencher os campos obrigatórios, clique em Guardar acionador.

gcloud

Quando cria uma função através da CLI gcloud, tem primeiro de implementar a função e, em seguida, criar um acionador. Siga estes passos para criar um acionador para a sua função:

  1. Execute o seguinte comando no diretório que contém o código de exemplo para implementar a sua função:

    gcloud run deploy FUNCTION \
            --source . \
            --function FUNCTION_ENTRYPOINT \
            --base-image BASE_IMAGE_ID \
            --region REGION
    

    Substituir:

    • FUNCTION com o nome da função que está a implementar. Pode omitir este parâmetro por completo, mas é-lhe pedido o nome se o omitir.

    • FUNCTION_ENTRYPOINT com o ponto de entrada da sua função no código-fonte. Este é o código que o Cloud Run executa quando a sua função é executada. O valor desta flag tem de ser um nome de função ou um nome de classe totalmente qualificado que exista no seu código-fonte.

    • BASE_IMAGE_ID com o ambiente de imagem base para a sua função. Para mais detalhes sobre as imagens base e os pacotes incluídos em cada imagem, consulte o artigo Imagens base de tempos de execução.

    • REGION com a Google Cloud região onde quer implementar a sua função. Por exemplo, europe-west1.

  2. Execute o seguinte comando para criar um acionador que filtra eventos:

    gcloud eventarc triggers create TRIGGER_NAME  \
        --location=EVENTARC_TRIGGER_LOCATION \
        --destination-run-service=FUNCTION  \
        --destination-run-region=REGION \
        --event-filters=type=google.cloud.firestore.document.v1.written \
        --event-filters=database='(default)' \
        --event-data-content-type=application/protobuf \
        --event-filters-path-pattern=document='messages/{pushId}' \
        --service-account=PROJECT_NUMBER-compute@developer.gserviceaccount.com
    

    Substituir:

    • TRIGGER_NAME com o nome do acionador.

    • EVENTARC_TRIGGER_LOCATION com a localização do acionador do Eventarc. Em geral, a localização de um acionador do Eventarc deve corresponder à localização do Google Cloud recurso que quer monitorizar para eventos. Na maioria dos cenários, também deve implementar a função na mesma região. Para mais informações, consulte o artigo Localizações do Eventarc.

    • FUNCTION com o nome da função que está a implementar.

    • REGION com a região do Cloud Run da função.

    • PROJECT_NUMBER com o seu Google Cloud número do projeto. Os acionadores do Eventarc estão associados a contas de serviço para serem usados como uma identidade quando invocam a sua função. A conta de serviço do seu acionador do Eventarc tem de ter autorização para invocar a sua função. Por predefinição, o Cloud Run usa a conta de serviço de computação predefinida.

    Cada sinalização event-filters especifica um tipo de evento, com a função a ser acionada apenas quando um evento cumpre todos os critérios especificados nas respetivas sinalizações event-filters. Cada acionador tem de ter uma flag event-filters que especifique um tipo de evento suportado, como um novo documento escrito no Firestore ou um ficheiro carregado para o Cloud Storage. Não pode alterar o tipo de filtro de eventos após a criação. Para alterar o tipo de filtro de eventos, tem de criar um novo acionador e eliminar o antigo. Opcionalmente, pode repetir a flag --event-filters com um filtro suportado no formato ATTRIBUTE=VALUE para adicionar mais filtros.

Terraform

Para criar um acionador do Eventarc para uma função do Cloud Run, consulte o artigo Crie um acionador com o Terraform.

Use os outros campos tal como estão:

  • --event-filters=type=google.cloud.firestore.document.v1.written especifica que a função é acionada quando um documento é criado, atualizado ou eliminado, de acordo com o google.cloud.firestore.document.v1.written tipo de evento.
  • --event-filters=database='(default)' especifica a base de dados do Firestore. Para o nome da base de dados predefinido, use (default).
  • --event-filters-path-pattern=document='messages/{pushId}' fornece o padrão do caminho dos documentos que devem ser monitorizados para detetar alterações relevantes. Este padrão de caminho indica que todos os documentos na coleção messages devem ser monitorizados. Para mais informações, consulte o artigo Compreenda os padrões de caminhos.

Teste a função Converter em maiúsculas

Para testar a função Convert to Uppercase que acabou de implementar, configure uma coleção denominada messages na sua base de dados do Firestore:

  1. Na Google Cloud consola, aceda à página de bases de dados do Firestore:

    Aceder ao Firestore

  2. Clique em Iniciar uma coleção.

  3. Especifique messages como o ID da coleção.

  4. Para começar a adicionar o primeiro documento da coleção, em Adicionar o primeiro documento, aceite o ID do documento gerado automaticamente.

  5. Para acionar a função implementada, adicione um documento em que o Nome do campo seja original e o Valor do campo seja minka.

  6. Quando guarda o documento, pode ver a palavra em minúsculas no campo de valor convertida em maiúsculas.

    Se, posteriormente, editar o valor do campo para incluir letras minúsculas, isso aciona novamente a função, convertendo todas as letras minúsculas em maiúsculas.

Limitações para funções

  • A ordenação não é garantida. As alterações rápidas podem acionar invocações de funções numa ordem inesperada.
  • Os eventos são entregues, pelo menos, uma vez, mas um único evento pode resultar em várias invocações de funções. Evite depender de mecanismos de execução única e escreva funções idempotentes.
  • Um acionador está associado a uma única base de dados. Não pode criar um acionador que corresponda a várias bases de dados.
  • A eliminação de uma base de dados não elimina automaticamente os acionadores dessa base de dados. O acionador deixa de enviar eventos, mas continua a existir até o eliminar.