Notificação de alteração de objetos

Use a notificação de alteração de objetos para informar a um aplicativo que um objeto foi atualizado ou adicionado a um bucket.

É melhor usar a notificação de alteração de objeto?

Geralmente, não convém usar a notificação de alteração de objeto. A ferramenta recomendada para gerar notificações que rastreiam alterações em objetos em buckets do Cloud Storage é notificações de Pub/Sub para Cloud Storage, uma vez que é a mais rápida, flexível, fácil de configurar e econômica. Para ver um guia passo a passo do uso de notificações do Pub/Sub para o Cloud Storage, consulte Como usar notificações do Pub/Sub para Cloud Storage.

Como funciona a notificação de alteração de objetos

Um aplicativo cliente pode enviar uma solicitação para monitorar as alterações nos objetos de um determinado bucket.

Para concluir uma solicitação de monitoramento, é necessário criar um novo canal de notificação. Um canal de notificação é o meio usado para enviar uma mensagem de notificação a um aplicativo que está monitorando um bucket. Atualmente, há apenas um tipo de canal de notificação compatível, o webhook.

Depois que um canal de notificação é inicializado, o Cloud Storage notifica o aplicativo sempre que um objeto é adicionado, atualizado ou removido do bucket. Por exemplo, quando você adiciona uma nova imagem a um bucket, um aplicativo pode ser notificado para criar uma miniatura.

Na figura abaixo é apresentado um exemplo de fluxo de dados para um aplicativo que processa notificações de alteração. Qualquer servidor de aplicativos que possa receber solicitações HTTPS POST pode ser usado para processar notificações de alteração.

Componentes da notificação de alteração de objetos
Componentes da notificação de alteração de objetos

Detalhes da notificação de alteração de objetos

Terminologia

A tabela a seguir contém uma descrição de vários termos usados na documentação da notificação de alteração de objetos:

Termo Descrição
URL do aplicativo O URL do seu aplicativo. É o endereço de destino das notificações que serão enviadas. Ele precisa ser um URL HTTPS. URLs HTTP não são permitidos.
Identificador do canal O identificador do canal de notificação. Ele precisa ser exclusivo dentro do bucket, ou seja, se houver vários canais de notificação em um único bucket, cada um precisa ter um identificador diferente. Esse identificador será enviado ao seu aplicativo com cada mensagem de notificação.
Identificador do recurso Um identificador opaco do recurso que está sendo monitorado. O identificador do recurso é necessário para interromper um canal de notificação. É possível recuperar esse identificador na resposta de uma solicitação de monitoramento ou no cabeçalho X-Goog-Resource-Id das mensagens de evento de notificação.
Token do cliente (Opcional) Os tokens do cliente podem ser usados para validar os eventos de notificação. Para fazer isso, defina um token do cliente personalizado na solicitação de monitoramento. As mensagens de notificação incluirão esse token para que você verifique se são autênticas.

Como monitorar um bucket

Para começar a monitorar eventos de notificação de alteração em um bucket, use o comando gsutil notification watchbucket:

gsutil notification watchbucket [-i ChannelId] [-t ClientToken] ApplicationUrl gs://BucketName

Isso criará um canal de notificação que envia eventos de notificação para o URL do aplicativo definido para esse bucket. O canal de notificação incluirá o token do cliente personalizado e o identificador do canal, quando especificados.

Para mais informações, execute o comando gsutil help notification watchbucket.

Um exemplo de solicitação POST gerada pelo gsutil para monitorar um bucket:

POST /storage/v1/b/BucketName/o/watch?alt=json HTTP/1.1
Host: storage.googleapis.com
Content-Length: 200
User-Agent: google-api-python-client/1.0
Content-Type: application/json
Authorization: Bearer oauth2_token

{
  "token": "ClientToken",
  "type": "web_hook",
  "id": "ChannelId",
  "address": "ApplicationUrl"
}

Autorização de notificação

Durante o monitoramento do bucket, o canal de notificação que está sendo criado será associado ao projeto no Console do Google Cloud correspondente ao aplicativo que iniciou a solicitação de API. Isso significa que, por exemplo, se um usuário conceder acesso a um aplicativo instalado ou da Web por meio de um fluxo OAuth2, o canal de notificação criado pelo aplicativo será associado ao projeto do aplicativo, e não ao projeto que contém o bucket que será monitorado.

Em um cenário de notificação de alteração de objetos, há três etapas para configurar a autorização:

Como criar uma conta de serviço

Como a conta de serviço está associada ao projeto, usá-la para monitorar um bucket criará um canal de notificação nesse projeto.

Use uma conta de serviço atual ou crie uma nova e faça o download da chave privada associada a ela.

Como configurar a gsutil para usar a conta de serviço

Para configurar a gsutil para usar a conta de serviço, use o SDK do Google Cloud para adicionar a conta de serviço como uma conta credenciada para trabalhar com recursos do Google Cloud, incluindo notificação de alteração de objeto. Depois de adicionar as credenciais, todos os comandos subsequentes da gsutil usarão as credenciais da conta de serviço.

Para criar credenciais baseadas na conta de serviço:

  1. Verifique se você tem a versão mais recente doSDK do Cloud. Para atualizar os componentes, execute:
    gcloud components update
    
  2. Use o comando gcloud auth activate-service-account e especifique o endereço de e-mail e a chave privada da conta de serviço.
    gcloud auth activate-service-account service-account-email --key-file path/to/key.p12
    

    em que:

    • service-account-email é o endereço de e-mail da conta de serviço, Você verá algo parecido com: 1234567890123-abcdefghijklmonpqrstuvwxz01234567@developer.gserviceaccount.com;
    • path/to/key.p12 é a chave que você foi solicitado a fazer o download quando criou a conta de serviço. Caso perca a chave, retorne para a página Credenciais no Console do Google Cloud e gere uma nova chave.
  3. Confirme se a conta de serviço é a conta credenciada ativa.
    $ gcloud auth list
    Credentialed accounts:
    - 1234567890123-abcdefghijklmonpqrstuvwxz01234567@developer.gserviceaccount.com (active)
    

    Você verá active ao lado das credenciais da conta de serviço. Agora, todos os comandos de notificação de objeto do gsutil executados usarão as credenciais da conta de serviço.

Como identificar um domínio para receber notificações

As solicitações de observação só funcionarão se o URL de notificação for um domínio permitido pelo projeto do canal de notificação.

Para permitir um domínio:

  1. Verifique se você é proprietário do domínio usando o processo de verificação do Search Console.
  2. No Console do Cloud, acesse a página Verificação de domínio.

    Acesse a página Verificação de domínio

  3. Clique em Adicionar domínio.
  4. Na caixa de diálogo Configurar notificações de webhook, insira o domínio a ser verificado.

    Caixa de diálogo

  5. Clique em Adicionar domínio.

    Para resolver problemas de confirmação de domínio, faça o seguinte:

    • O domínio precisa estar registrado no Search Console com um URL https:// ou ter sido confirmado com o método de confirmação do provedor de nome de domínio.
    • Certifique-se de que você é proprietário ou editor do projeto do Console do Cloud consultando Membros e permissões do projeto e que você é o proprietário do domínio do site que receberá as notificações. Se você não é proprietário de site no domínio, entre em contato com o proprietário do domínio para ser adicionado como proprietário verificado. Consulte Adicionar ou remover proprietários.
    • É possível usar o APIs Explorer do Google no Search Console e listar os sites no domínio, em especial, ver se a propriedade siteUrl do domínio começa com https://.

Como remover um canal de notificação

Para interromper um canal de notificação, use o comando gsutil notification stopchannel:

gsutil notification stopchannel ChannelId ResourceId

Isso interromperá todos os eventos de notificação para o par de identificadores do recurso e do canal especificados. Outros canais ativos do mesmo recurso não serão afetados. Os identificadores do recurso e do canal estão na resposta da solicitação de monitoramento ou no corpo das mensagens de evento de notificação.

Para mais informações, execute o comando gsutil help notification stopchannel.

Veja abaixo um exemplo de solicitação POST gerada pela gsutil para interromper um canal:

POST /storage/v1/channels/stop HTTP/1.1
Host: storage.googleapis.com
Content-Length: 200
User-Agent: google-api-python-client/1.0
Content-Type: application/json
Authorization: Bearer oauth2_token

{
  "resourceId": "ResourceId",
  "id": "ChannelId"
}

Tipos de mensagens de evento de notificação

Sincronização

Após a emissão de uma solicitação de monitoramento, um canal de notificação novo é criado e um evento de notificação é enviado. Depois de receber o evento de sincronização, todas as alterações posteriores no bucket serão enviadas ao URL do aplicativo configurado para o canal.

A notificação será enviada ao URL configurado para o aplicativo como uma solicitação POST. A solicitação não tem corpo. Os metadados da notificação de sincronização estão contidos nos cabeçalhos da solicitação. Veja abaixo um exemplo de solicitação de notificação de sincronização:

POST /ApplicationUrlPath
Accept: */*
Content-Type: application/json; charset="utf-8"
Content_Length: 0
Host: ApplicationUrlHost
X-Goog-Channel-Id: ChannelId
X-Goog-Channel-Token: ClientToken
X-Goog-Resource-Id: ResourceId
X-Goog-Resource-State: sync
X-Goog-Resource-Uri: https://storage.googleapis.com/storage/v1/b/BucketName/o?alt=json

Adição, atualização ou exclusão de objetos

Um evento de notificação é enviado quando um objeto novo é adicionado a um bucket, quando o conteúdo ou os metadados de um objeto atual são modificados ou quando um objeto é excluído de um bucket.

A notificação será enviada ao URL configurado para o aplicativo como uma solicitação POST. O corpo da solicitação contém uma mensagem em código JSON, conforme mostrado na solicitação de notificação a seguir:

POST /ApplicationUrlPath
Accept: */*
Content-Length: 1097
Content-Type: application/json; charset="utf-8"
Host: ApplicationUrlHost
X-Goog-Channel-Id: ChannelId
X-Goog-Channel-Token: ClientToken
X-Goog-Resource-Id: ResourceId
X-Goog-Resource-State: ResourceState
X-Goog-Resource-Uri: https://storage.googleapis.com/storage/v1/b/BucketName/o?alt=json

{
 "kind": "storage#object",
 "id": "BucketName/ObjectName",
 "selfLink": "https://www.googleapis.com/storage/v1/b/BucketName/o/ObjectName",
 "name": "ObjectName",
 "bucket": "BucketName",
 "generation": "1367014943964000",
 "metageneration": "1",
 "contentType": "application/octet-stream",
 "updated": "2013-04-26T22:22:23.832Z",
 "size": "10",
 "md5Hash": "xHZY0QLVuYng2gnOQD90Yw==",
 "mediaLink": "https://storage.googleapis.com/storage/v1/b/BucketName/o/ObjectName?generation=1367014943964000&alt=media",
 "owner": {
  "entity": "user-jane@gmail.com"
 },
 "crc32c": "C7+82w==",
 "etag": "COD2jMGv6bYCEAE="
}
onde ResourceState é:
  • exists: para adições e atualizações de objetos;
  • not_exists: para exclusões de objetos.

O conteúdo da mensagem JSON incluirá a representação atual do objeto, conforme descrito na descrição do recurso de objeto.

Entrega confiável

A notificação de alteração de objeto tentará enviar notificações para seu aplicativo de maneira confiável. No entanto, as notificações podem sofrer atrasos indefinidamente e a pontualidade não é garantida. Como seu aplicativo talvez nem sempre estará disponível, as regras a seguir determinam como ocorre a entrega de notificações:

  • Se a tentativa de entrega de uma notificação falhar, serão feitas novas tentativas. O intervalo entre as novas tentativas de entrega é determinado por um algoritmo de espera exponencial, que começa com uma nova tentativa 30 segundos após a falha inicial. As demais tentativas de entrega subsequentes são feitas em intervalos crescentes, até o máximo de 90 minutos. Observe que os intervalos entre novas tentativas são um pouco aleatórios. Portanto, eles não ocorrem em valores exponenciais exatos. Depois que for atingido o intervalo máximo de 90 minutos, as tentativas subsequentes serão feitas a cada 90 minutos por sete dias. Se não for possível entregar a notificação nesse período, ela será limpa.
  • Caso não seja possível se comunicar com seu aplicativo após 20 segundos ou se ele responder com um dos códigos de resposta HTTP a seguir, a tentativa de entrega de notificação será tratada como uma falha e uma nova tentativa será feita:
    • 500 Internal Server Error
    • 502 Bad Gateway
    • 503 Service Unavailable
    • 504 Gateway Timeout
  • Se seu aplicativo responder com um dos códigos de resposta HTTP a seguir, a notificação será tratada como entregue:
    • 102 Processing
    • 200 OK
    • 201 Created
    • 202 Accepted
    • 204 No Content
  • Quaisquer outros códigos de resposta HTTP retornados pelo aplicativo são tratados como falhas permanentes. Nesses casos, não são feitas novas tentativas.

Exemplo de aplicativo cliente

Nesta seção, explicamos como criar um aplicativo cliente do App Engine que processa eventos de notificação de alteração.

A figura a seguir mostra a linha do tempo dos eventos básicos envolvidos no recebimento de uma notificação, desde a criação de um bucket até o processamento dos eventos de notificação de alteração relacionados:

Linha do tempo da notificação de alteração de objetos
Linha do tempo da notificação de alteração de objetos

O aplicativo do exemplo contém uma classe chamada MainPage. Quando o usuário atualiza ou adiciona um objeto ao bucket, a classe MainPage processa o evento de notificação. Para simplificar, o método post que faz o processamento real registra uma mensagem com o horário em que a notificação foi recebida. É possível substituir esse código pela lógica de processamento que você de fato usa. Caso você ainda não se sinta à vontade para desenvolver aplicativos do App Engine, tente implantar uma amostra de aplicativo ou seguir um tutorial antes de continuar.

  1. Configurar o aplicativo
    Crie o arquivo de configuração app.yaml para especificar o aplicativo cliente que processa os eventos de notificação de alteração do intervalo.
    application: APPLICATION
    version: 1
    runtime: python27
    api_version: 1
    threadsafe: true
    
    handlers:
    - url: /.*
      script: change_notification_client.app
    
  2. Como criar o aplicativo.
    Veja no exemplo a seguir como implementar um aplicativo cliente para o processamento de eventos de notificação de alteração de um intervalo. Dê a ele o nome de change_notification_client.py e implante-o:
    """Notification handling for Google Cloud Storage."""
    
    import json
    import logging
    
    import webapp2
    
    class MainPage(webapp2.RequestHandler):
      """Process notification events."""
      def get(self):
        logging.info("Get request to notification page.")
        self.response.write("Welcome to the notification app.")
    
      def post(self):  # pylint: disable-msg=C6409
        """Process the notification event.
    
        This method is invoked when the notification channel is first created with
        a sync event, and then subsequently every time an object is added to the
        bucket, updated (both content and metadata) or removed. It records the
        notification message in the log.
        """
    
        logging.debug(
            '%s\n\n%s',
            '\n'.join(['%s: %s' % x for x in self.request.headers.iteritems()]),
            self.request.body)
    
        # The following code is for demonstration. Replace
        # it with your own notification processing code.
    
        if 'X-Goog-Resource-State' in self.request.headers:
          resource_state = self.request.headers['X-Goog-Resource-State']
          if resource_state == 'sync':
            logging.info('Sync message received.')
          else:
            an_object = json.loads(self.request.body)
            bucket = an_object['bucket']
            object_name = an_object['name']
            logging.info('%s/%s %s', bucket, object_name, resource_state)
        else:
          logging.info("Other post.")
    
    logging.getLogger().setLevel(logging.DEBUG)
    app = webapp2.WSGIApplication([('/', MainPage)], debug=True)
    
  3. Como atribuir a permissão de acesso do aplicativo ao bucket.
    Se seu bucket pertencer a uma conta de serviço diferente do seu aplicativo do App Engine, execute o comando a seguir para conceder ao bucket o acesso de PROPRIETÁRIO do aplicativo:
    gsutil acl ch -u ApplicationId@appspot.gserviceaccount.com:OWNER gs://BucketName
    
  4. Como começar a monitorar alterações de objetos do bucket
    Monitore o bucket com a gsutil para criar um canal de notificação para seu aplicativo:
    gsutil notification watchbucket ApplicationUrl gs://BucketName
    
    em que ApplicationUrl é o URL do seu aplicativo do App Engine. Por exemplo, https://ApplicationId.appspot.com/.
  5. Como testar o aplicativo
    Para ver se o aplicativo funciona conforme esperado, execute estas etapas:
    1. Para garantir que o aplicativo foi implantado e funciona corretamente, execute o comando curl a seguir:
      curl -X Post https://APPLICATION_ID.appspot.com
      
      Caso você tenha usado seu próprio nome de domínio para implantar o aplicativo, use-o em vez de appspot.com no comando anterior.
    2. Acesse a página do Stackdriver Logging do seu projeto. Atualize a lista das mensagens registradas, se necessário. Verifique se a mensagem de registro emitida pelo aplicativo foi registrada.
    3. Adicione um objeto ao bucket. Você pode usar a ferramenta gsutil da seguinte maneira:
      gsutil cp ObjectName gs://BucketName/
      
      O Cloud Storage notifica o aplicativo que, em seguida, registra uma mensagem.
    4. Acesse a página do Stackdriver Logging do seu projeto. Atualize a lista de mensagens registradas e encontre aquela referente à cópia do objeto.
  6. Como remover o canal de notificação
    Remova o canal de notificação especificando os identificadores do canal e do recurso que foram retornados quando você emitiu o comando de notificação para monitorar bucket.
    gsutil notification stopchannel CHANNEL_ID RESOURCE_IDENTIFIER