Gatilhos do Google Cloud Storage

O Cloud Functions usa funções orientadas a eventos para processar eventos pela Infraestrutura do Cloud. Por exemplo, o Cloud Functions pode responder a notificações de alteração surgidas do Google Cloud Storage. Essas notificações podem ser configuradas para serem acionadas em resposta a vários eventos dentro de um bucket: criação de objetos, exclusão, arquivamento e atualizações de metadados.

Tipos de evento

Os eventos do Cloud Storage usados pelo Cloud Functions se baseiam em Notificações do Cloud Pub/Sub para o Google Cloud Storage e são fornecidos no formato da API JSON do Cloud Storage.

As funções acionadas pelo armazenamento aceitam quatro tipos de gatilho. Esses valores de tipo de gatilho são usados na implantação da função para especificar quais eventos do Cloud Storage acionarão as funções:

Cógido de função de amostra

O exemplo de função a seguir registra dados relevantes quando ocorre um evento.

Especifique o tipo de gatilho ao implantar a função. Por exemplo, o exemplo de implantação abaixo usa a função para registrar toda vez que um objeto é criado ao especificar o tipo de gatilho google.storage.object.finalize.

Para ver um tutorial completo sobre como executar esse código, consulte o tutorial do Cloud Storage:

Node.js

 
/**
 * Generic background Cloud Function to be triggered by Cloud Storage.
 *
 * @param {object} file The Cloud Storage file metadata.
 * @param {object} context The event metadata.
 */
exports.helloGCS = (file, context) => {
  console.log(`  Event: ${context.eventId}`);
  console.log(`  Event Type: ${context.eventType}`);
  console.log(`  Bucket: ${file.bucket}`);
  console.log(`  File: ${file.name}`);
  console.log(`  Metageneration: ${file.metageneration}`);
  console.log(`  Created: ${file.timeCreated}`);
  console.log(`  Updated: ${file.updated}`);
};

Python

 
def hello_gcs(event, context):
    """Background Cloud Function to be triggered by Cloud Storage.
       This generic function logs relevant data when a file is changed.

    Args:
        event (dict):  The dictionary with data specific to this type of event.
                       The `data` field contains a description of the event in
                       the Cloud Storage `object` format described here:
                       https://cloud.google.com/storage/docs/json_api/v1/objects#resource
        context (google.cloud.functions.Context): Metadata of triggering event.
    Returns:
        None; the output is written to Stackdriver Logging
    """

    print('Event ID: {}'.format(context.event_id))
    print('Event type: {}'.format(context.event_type))
    print('Bucket: {}'.format(event['bucket']))
    print('File: {}'.format(event['name']))
    print('Metageneration: {}'.format(event['metageneration']))
    print('Created: {}'.format(event['timeCreated']))
    print('Updated: {}'.format(event['updated']))

Go

 

// Package helloworld provides a set of Cloud Functions samples.
package helloworld

import (
	"context"
	"fmt"
	"log"
	"time"

	"cloud.google.com/go/functions/metadata"
)

// GCSEvent is the payload of a GCS event.
type GCSEvent struct {
	Kind                    string                 `json:"kind"`
	ID                      string                 `json:"id"`
	SelfLink                string                 `json:"selfLink"`
	Name                    string                 `json:"name"`
	Bucket                  string                 `json:"bucket"`
	Generation              string                 `json:"generation"`
	Metageneration          string                 `json:"metageneration"`
	ContentType             string                 `json:"contentType"`
	TimeCreated             time.Time              `json:"timeCreated"`
	Updated                 time.Time              `json:"updated"`
	TemporaryHold           bool                   `json:"temporaryHold"`
	EventBasedHold          bool                   `json:"eventBasedHold"`
	RetentionExpirationTime time.Time              `json:"retentionExpirationTime"`
	StorageClass            string                 `json:"storageClass"`
	TimeStorageClassUpdated time.Time              `json:"timeStorageClassUpdated"`
	Size                    string                 `json:"size"`
	MD5Hash                 string                 `json:"md5Hash"`
	MediaLink               string                 `json:"mediaLink"`
	ContentEncoding         string                 `json:"contentEncoding"`
	ContentDisposition      string                 `json:"contentDisposition"`
	CacheControl            string                 `json:"cacheControl"`
	Metadata                map[string]interface{} `json:"metadata"`
	CRC32C                  string                 `json:"crc32c"`
	ComponentCount          int                    `json:"componentCount"`
	Etag                    string                 `json:"etag"`
	CustomerEncryption      struct {
		EncryptionAlgorithm string `json:"encryptionAlgorithm"`
		KeySha256           string `json:"keySha256"`
	}
	KMSKeyName    string `json:"kmsKeyName"`
	ResourceState string `json:"resourceState"`
}

// HelloGCS consumes a GCS event.
func HelloGCS(ctx context.Context, e GCSEvent) error {
	meta, err := metadata.FromContext(ctx)
	if err != nil {
		return fmt.Errorf("metadata.FromContext: %v", err)
	}
	log.Printf("Event ID: %v\n", meta.EventID)
	log.Printf("Event type: %v\n", meta.EventType)
	log.Printf("Bucket: %v\n", e.Bucket)
	log.Printf("File: %v\n", e.Name)
	log.Printf("Metageneration: %v\n", e.Metageneration)
	log.Printf("Created: %v\n", e.TimeCreated)
	log.Printf("Updated: %v\n", e.Updated)
	return nil
}

Java

import com.google.cloud.functions.BackgroundFunction;
import com.google.cloud.functions.Context;
import functions.eventpojos.GcsEvent;
import java.util.logging.Logger;

public class HelloGcs implements BackgroundFunction<GcsEvent> {
  private static final Logger logger = Logger.getLogger(HelloGcs.class.getName());

  @Override
  public void accept(GcsEvent event, Context context) {
    logger.info("Event: " + context.eventId());
    logger.info("Event Type: " + context.eventType());
    logger.info("Bucket: " + event.getBucket());
    logger.info("File: " + event.getName());
    logger.info("Metageneration: " + event.getMetageneration());
    logger.info("Created: " + event.getTimeCreated());
    logger.info("Updated: " + event.getUpdated());
  }
}

C#

using CloudNative.CloudEvents;
using Google.Cloud.Functions.Framework;
using Google.Events.Protobuf.Cloud.Storage.V1;
using Microsoft.Extensions.Logging;
using System.Threading;
using System.Threading.Tasks;

namespace HelloGcs
{
    public class Function : ICloudEventFunction<StorageObjectData>
    {
        private readonly ILogger _logger;

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

        public Task HandleAsync(CloudEvent cloudEvent, StorageObjectData data, CancellationToken cancellationToken)
        {
            _logger.LogInformation("Event: {event}", cloudEvent.Id);
            _logger.LogInformation("Event Type: {type}", cloudEvent.Type);
            _logger.LogInformation("Bucket: {bucket}", data.Bucket);
            _logger.LogInformation("File: {file}", data.Name);
            _logger.LogInformation("Metageneration: {metageneration}", data.Metageneration);
            _logger.LogInformation("Created: {created:s}", data.TimeCreated?.ToDateTimeOffset());
            _logger.LogInformation("Updated: {updated:s}", data.Updated?.ToDateTimeOffset());
            return Task.CompletedTask;
        }
    }
}

Ruby

require "functions_framework"

FunctionsFramework.cloud_event "hello_gcs" do |event|
  # The event parameter is a CloudEvents::Event::V1 object.
  # See https://cloudevents.github.io/sdk-ruby/latest/CloudEvents/Event/V1.html
  payload = event.data

  logger.info "Event: #{event.id}"
  logger.info "Event Type: #{event.type}"
  logger.info "Bucket: #{payload['bucket']}"
  logger.info "File: #{payload['name']}"
  logger.info "Metageneration: #{payload['metageneration']}"
  logger.info "Created: #{payload['timeCreated']}"
  logger.info "Updated: #{payload['updated']}"
end

PHP


use Google\CloudFunctions\CloudEvent;

function helloGCS(CloudEvent $cloudevent)
{
    $log = fopen(getenv('LOGGER_OUTPUT') ?: 'php://stderr', 'wb');
    $data = $cloudevent->getData();
    fwrite($log, 'Event: ' . $cloudevent->getId() . PHP_EOL);
    fwrite($log, 'Event Type: ' . $cloudevent->getType() . PHP_EOL);
    fwrite($log, 'Bucket: ' . $data['bucket'] . PHP_EOL);
    fwrite($log, 'File: ' . $data['name'] . PHP_EOL);
    fwrite($log, 'Metageneration: ' . $data['metageneration'] . PHP_EOL);
    fwrite($log, 'Created: ' . $data['timeCreated'] . PHP_EOL);
    fwrite($log, 'Updated: ' . $data['updated'] . PHP_EOL);
}

Como especificar o tipo de gatilho na implantação

O comando gcloud a seguir implanta a função com um gatilho object.finalize.

Node.js

gcloud functions deploy helloGCS \
--runtime nodejs14 \
--trigger-resource YOUR_TRIGGER_BUCKET_NAME \
--trigger-event google.storage.object.finalize
É possível usar os seguintes valores para a sinalização --runtime para especificar sua versão preferida do Node.js:
  • nodejs16 (visualização)
  • nodejs14 (recomendado)
  • nodejs12
  • nodejs10

Python

gcloud functions deploy hello_gcs \
--runtime python39 \
--trigger-resource YOUR_TRIGGER_BUCKET_NAME \
--trigger-event google.storage.object.finalize
É possível usar os seguintes valores da sinalização --runtime para especificar a versão preferencial do Python:
  • python39 (recomendado)
  • python38
  • python37

Go

gcloud functions deploy HelloGCS \
--runtime go113 \
--trigger-resource YOUR_TRIGGER_BUCKET_NAME \
--trigger-event google.storage.object.finalize
É possível usar os seguintes valores para a sinalização --runtime para especificar sua versão Go preferencial:
  • go116 (visualização)
  • go113 (recomendado)
  • go111

Java

gcloud functions deploy java-gcs-function \
--entry-point functions.HelloGcs \
--runtime java11 \
--memory 512MB \
--trigger-resource YOUR_TRIGGER_BUCKET_NAME \
--trigger-event google.storage.object.finalize

C#

gcloud functions deploy csharp-gcs-function \
--entry-point HelloGcs.Function \
--runtime dotnet3 \
--trigger-resource YOUR_TRIGGER_BUCKET_NAME \
--trigger-event google.storage.object.finalize

Ruby

gcloud functions deploy hello_gcs --runtime ruby27 \
--trigger-resource YOUR_TRIGGER_BUCKET_NAME \
--trigger-event google.storage.object.finalize
Use os seguintes valores da sinalização --runtime para especificar a versão do Ruby que você quer usar:
  • ruby27 (recomendado)
  • ruby26

PHP

gcloud functions deploy helloGCS --runtime php74 \
--trigger-resource YOUR_TRIGGER_BUCKET_NAME \
--trigger-event google.storage.object.finalize

em que YOUR_TRIGGER_BUCKET_NAME é o nome do bucket do Cloud Storage que a função vai monitorar.

Objeto finalize

Valor do tipo de gatilho: google.storage.object.finalize

Esse evento é enviado quando um novo objeto é criado (ou um objeto existente é substituído e uma nova geração desse objeto é criada) no bucket.

Objeto delete

Valor do tipo de gatilho: google.storage.object.delete

Este evento é enviado quando um objeto é excluído permanentemente. Dependendo da configuração do controle de versão do objeto de um bucket isso significa:

  • Para buckets do controle de versões, ele só é enviado quando uma versão é excluída permanentemente (mas não quando um objeto é arquivado).

  • Para buckets sem controle de versões, ele é enviado quando um objeto é excluído ou substituído.

Arquivamento do objeto

Valor do tipo de gatilho: google.storage.object.archive

Este evento é enviado quando uma versão ativa de um objeto é arquivada ou excluída.

Este só é enviado para buckets com controle de versão.

Atualização de metadados do objeto

Valor do tipo de gatilho: google.storage.object.metadataUpdate

Este evento é enviado quando os metadados de um objeto existente mudam.

Estrutura do evento

Os dados de eventos de armazenamento são entregues no formato object do Cloud Storage.

Mecanismo de envio do evento

Os eventos são entregues usando notificações do Pub/Sub do Cloud Storage.

Limite de notificações

É possível ter até 10 configurações de notificação definidas no bucket para acionar um determinado evento. A configuração de muitas notificações para o mesmo bucket pode exceder o limite de notificações do bucket e impossibilitar a criação da função, conforme indicado por este erro:

Cloud Storage bucket ...: Pub/Sub notification limit reached

Se você atingir o limite, não será possível criar uma função até tomar medidas corretivas, como remover as notificações.

Saiba mais sobre as cotas e os limites de solicitação do Cloud Storage.

Permissões

É necessário ter permissões suficientes no projeto que receberá as notificações. Isso inclui garantir que você faça o seguinte:

  1. Encontre o endereço de e-mail da conta de serviço associada ao projeto que contém o bucket do Cloud Storage.

  2. Use esse endereço de e-mail para atribuir ao agente de serviço o papel do IAM pubsub.publisher para o tópico do Pub/Sub relevante.

Saiba mais sobre o recurso Como configurar notificações do Pub/Sub para Cloud Storage.

Gatilhos legados do Cloud Storage

O comando gcloud abaixo implanta uma função que é acionada por notificações de alteração de objeto legadas em um bucket específico. Geralmente, as notificações do Cloud Pub/Sub são mais fáceis de usar, mais flexíveis e mais eficientes do que as notificações de alteração do objeto. Porém, essas notificações legadas são compatíveis com funções legadas que já consomem esses eventos.

gcloud functions deploy YOUR_FUNCTION_NAME \
--trigger-resource YOUR_TRIGGER_BUCKET_NAME \
--trigger-event providers/cloud.storage/eventTypes/object.change \
FLAGS...
Argumento Descrição
--trigger-resource NAME O nome do bucket do Cloud Storage em que a função detecta alterações.
--trigger-event NAME O nome do tipo de evento que a função quer receber. Nesse caso, é o evento legado de object.change.
FLAGS... Sinalizações adicionais que você precisa especificar durante a implantação, como --runtime. Para uma referência completa, consulte a documentação gcloud functions deploy.

Próximas etapas

Consulte o Tutorial do Cloud Storage para um exemplo de como implementar uma função orientada a eventos que é acionada pelo Cloud Storage.