Notificación de cambio de objeto

La notificación de cambio de objeto puede usarse para notificar a una aplicación sobre la actualización o adición de un objeto a un depósito.

¿Deberías usar la notificación de cambio de objeto?

Por lo general, no debes usar la notificación de cambio de objeto. La herramienta recomendada para generar notificaciones de seguimiento de los cambios en los objetos en tus depósitos de Cloud Storage es Notificaciones de Pub/Sub para Cloud Storage, porque es más rápida, flexible, fácil de configurar y rentable. Si deseas obtener una guía paso a paso sobre el uso de notificaciones de Pub/Sub para Cloud Storage, consulta Registro de cambios de objeto.

Cómo funciona la notificación de cambio de objeto

Una aplicación cliente puede enviar una solicitud para observar cambios en los objetos de un depósito en particular.

Cuando completas una solicitud de observación, se crea un canal de notificación nuevo. Un canal de notificación es el medio por el que un mensaje de notificación se envía a una aplicación que observa un depósito. En la actualidad, el único tipo de canal de notificación que se admite es un webhook.

Después de que se inicia un canal de notificación, Cloud Storage notifica a la aplicación cada vez que se agrega, actualiza o quita un objeto del depósito. Por ejemplo, cuando agregas una foto nueva a un depósito, se puede notificar a una aplicación a fin de crear una miniatura.

En la figura a continuación, se muestra un ejemplo del flujo de datos para una aplicación que procesa notificaciones de cambios. Cualquier servidor de aplicaciones que pueda recibir solicitudes POST de HTTPS puede usarse para procesar notificaciones de cambios.

Componentes de notificación de cambio de objeto
Componentes de notificación de cambio de objeto

Detalles de la notificación de cambio de objeto

Terminología

En la tabla siguiente, encontrarás la descripción de varios términos usados en toda la documentación de notificación de cambio de objeto.

Término Descripción
URL de la aplicación La URL de tu aplicación. Esta es la dirección a donde se enviarán las notificaciones. Ten en cuenta que debe tratarse de una URL HTTPS, ya que las URL HTTP no están permitidas.
Identificador de canal El identificador para un canal de notificación. Debe ser único en un depósito específico, es decir, si existen varios canales de notificación para un solo depósito, cada canal de notificación debe tener un identificador de canal distinto. Este identificador se enviará a tu aplicación junto con cada mensaje de notificación.
Identificador de recursos Un identificador opaco para el recurso que se observa. El identificador de recursos es necesario para detener un canal de notificación. Puedes recuperar este identificador desde la respuesta a una solicitud de observación o desde el encabezado X-Goog-Resource-Id de mensajes de eventos de notificación.
Token cliente (Opcional) Se pueden usar los tokens cliente para validar los eventos de notificaciones. Para ello, configura un token cliente personalizado con tu solicitud de observación. Los mensajes de notificación contendrán este token para que puedas verificar que sean auténticos.

Observa un depósito

A fin de comenzar a observar un depósito para los eventos de notificación de cambio, puedes usar el comando gsutil notification watchbucket:

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

Esto creará un canal de notificación que envía los eventos de notificación a la URL de la aplicación especificada para el depósito en cuestión. El canal de notificación incluirá el token cliente personalizado y el identificador de canal, si se especifica.

Para obtener más información sobre este comando, ejecuta gsutil help notification watchbucket.

Esta es una solicitud POST de ejemplo generada por gsutil para observar un depósito:

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"
}

Autorización de notificación

Cuando se observa un depósito, el canal de notificación que se crea estará asociado al proyecto de Google Cloud Console de la aplicación que inicia la solicitud a la API. Esto significa que, por ejemplo, si un usuario otorga acceso a una aplicación instalada o a una aplicación web a través de un flujo de OAuth2, un canal de notificación creado por la aplicación se asociará al proyecto de la aplicación, no al proyecto que contiene el depósito que se observa.

Existen tres pasos para configurar la autorización en una situación de notificación de cambio de objeto:

Crea una cuenta de servicio

Dado que una cuenta de servicio está asociada a un proyecto, usarla para observar un depósito creará un canal de notificación en el proyecto de la cuenta de servicio.

Debes usar una cuenta de servicio existente o crear una nueva, y descargar la clave privada asociada.

Configura gsutil para que use una cuenta de servicio

Si deseas configurar gsutil para que use la cuenta de servicio, puedes usar el SDK de Google Cloud a fin de agregar la cuenta de servicio como una cuenta con credenciales que se use con el fin de trabajar con recursos de Google Cloud, incluida la notificación de cambio de objeto. Luego de agregar las credenciales, todos los comandos de gsutil posteriores usarán las credenciales de la cuenta de servicio.

Para crear credenciales basadas en la cuenta de servicio, sigue estos pasos:

  1. Asegúrate de tener la última versión del SDK de Cloud. Puedes actualizar los componentes si ejecutas el siguiente comando:
    gcloud components update
    
  2. Usa el comando de gcloud auth activate-service-account y especifica la dirección de correo electrónico y la clave privada de la cuenta de servicio.
    gcloud auth activate-service-account service-account-email --key-file path/to/key.p12
    

    donde:

    • service-account-email es la dirección de correo electrónico de la cuenta de servicio. Será similar a esta: 1234567890123-abcdefghijklmonpqrstuvwxz01234567@developer.gserviceaccount.com
    • path/to/key.p12 es la clave que se te solicitó descargar cuando creaste la cuenta de servicio. Si perdiste la clave, puedes volver a la página Credenciales en Google Cloud Platform Console y generar una nueva.
  3. Confirma que la cuenta de servicio es la cuenta con credenciales activas.
    $ gcloud auth list
    Credentialed accounts:
    - 1234567890123-abcdefghijklmonpqrstuvwxz01234567@developer.gserviceaccount.com (active)
    

    Deberías ver active en las credenciales de la cuenta de servicio. Ahora, cualquier comando de notificación de objeto gsutil que ejecutes usará las credenciales de la cuenta de servicio.

Identifica un dominio para recibir notificaciones

Las solicitudes de observación solo se realizarán de forma correcta si la URL de la notificación es un dominio perteneciente a la lista blanca del proyecto del canal de notificación.

Para incluir un dominio en la lista blanca, usa lo siguiente:

  1. Verifica que eres el propietario del dominio mediante el proceso de verificación de Search Console.
  2. En GCP Console, ve a la página Verificación del dominio.

    Ir a la página Credenciales

  3. Haz clic en Agregar dominio (Add domain).
  4. En el cuadro de diálogo Configura notificaciones de webhook (Configure webhook notifications), ingresa el dominio que deseas verificar.

    Configura el cuadro de diálogo de notificaciones de webhook

  5. Haz clic en Agregar dominio (Add Domain).

    Para solucionar problemas sobre la verificación del dominio, haz lo siguiente:

    • El dominio debe estar registrado en Search Console con una URL https:// o estar verificado con el método de verificación Proveedor del nombre de dominio.
    • Asegúrate de que eres el propietario o editor del proyecto de GCP Console (consulta Miembros del proyecto y permisos) y eres el propietario del sitio del dominio que recibirá notificaciones. Si no eres el propietario del sitio del dominio, comunícate con el propietario del dominio para que te agregue como propietario verificado (consulta Agregar o quitar propietarios).
    • Puedes usar el Explorador de API de Google para Herramientas para webmasters de Google a fin de generar una lista de sitios en el dominio y, en particular, ver si la propiedad siteUrl del dominio comienza con https://.

Quita un canal de notificación

Para detener un canal de notificación, puedes usar el comando gsutil notification stopchannel:

gsutil notification stopchannel ChannelId ResourceId

Esto detendrá todos los eventos de notificación del identificador de recursos especificado y la sincronización del identificador de canal. Los canales activos adicionales para el mismo recurso no se verán afectados. Los identificadores de recursos y de canales se pueden encontrar en la respuesta de una solicitud de observación o en el cuerpo de los mensajes de eventos de notificación.

Para obtener más información sobre este comando, ejecuta gsutil help notification stopchannel.

Esta es una solicitud POST de ejemplo generada por gsutil para detener un 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 mensajes de eventos de notificación

Sync

Un evento de notificación se envía cuando se crea un canal de notificación nuevo luego de emitir una solicitud de observación. Después de recibir el evento de sincronización, todos los cambios posteriores en el depósito se enviarán a la URL de la aplicación configurada para el canal.

  <p>The notification will be sent as a POST request to the configured application URL. There is no body in the request. The sync notification metadata is contained in the request's headers. The following is an example of the <strong>sync</strong> notification request:</p>
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
</dd>
<dt id="_Type_AddUpdateDel">Object Addition, Update, or Deletion</dt>
<dd>
  <p>A notification event is sent when a new object is added to a bucket, an existing object's
    content or metadata has been modified, or an object is deleted from a bucket.</p>

  <p>The notification will be sent as a POST request to the configured application URL. The body
    of the request contains a JSON-encoded message as shown in the following notification request:
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="
}
En el ejemplo anterior, ResourceState es lo siguiente:
  • exists: para adiciones y actualizaciones de objetos
  • not_exists: para la eliminación de objetos

El contenido del mensaje JSON también incluye la representación actual del objeto como se describe en la sección de descripción del recurso de objeto.

Entrega confiable

La notificación de cambio de objeto intentará entregar notificaciones a tu aplicación de un modo confiable. Sin embargo, ten en cuenta que las notificaciones se pueden retrasar de forma indefinida y no se garantiza la puntualidad. Dado que es posible que tu aplicación no esté siempre disponible, se deben seguir las siguientes reglas cuando se entregan notificaciones:

  • Si el intento de entrega de una notificación falla, se realizarán más intentos. El intervalo entre los intentos de entrega adicionales se determina mediante un algoritmo de retirada exponencial que comienza con un reintento de 30 segundos después de la falla inicial. Se intentarán entregas posteriores a intervalos mayores, hasta un intervalo máximo de 90 minutos. Ten en cuenta que los intervalos de reintento posteriores son un poco aleatorios, por lo que no se producen en valores exponenciales exactos. Después de que se alcanza el intervalo máximo de reintentos de 90 minutos, los reintentos posteriores continúan cada 90 minutos durante 7 días. Si no se puede entregar la notificación en ese tiempo, se borrará de forma definitiva.
  • Si no puedes acceder a tu aplicación después de 20 segundos o si tu aplicación responde con uno de los códigos de respuesta HTTP siguientes, el intento de entrega de notificación se considera un error y vuelve a realizarse:
    • 500 Internal Server Error
    • 502 Bad Gateway
    • 503 Service Unavailable
    • 504 Gateway Timeout
  • Si tu aplicación responde con uno de los códigos de respuesta HTTP siguientes, se considera que la notificación se entregó de forma correcta:
    • 102 Processing
    • 200 OK
    • 201 Created
    • 202 Accepted
    • 204 No Content
  • Cualquier otro código de respuesta HTTP que muestre tu aplicación se considera una falla permanente y no vuelve a intentarse.

Ejemplo de aplicación cliente

En esta sección, se explica cómo crear una aplicación cliente de App Engine que procesa eventos de notificación de cambio.

En la imagen siguiente, se muestra el cronograma de los eventos básicos que intervienen en la recepción de una notificación, desde la creación de un depósito hasta el procesamiento de eventos de notificación de cambio relacionados.

Cronograma de la notificación de cambio de objeto
Cronograma de la notificación de cambio de objeto

La aplicación de ejemplo contiene una clase llamada MainPage. Cuando el usuario actualiza un objeto o lo agrega al depósito, la clase MainPage procesa el evento de notificación. Para hacerlo más simple, el método post que realiza el procesamiento real registra un mensaje con la hora en que se recibió la notificación. Puedes reemplazar este código por tu lógica de procesamiento real. Si aún no te sientes cómodo con el desarrollo de aplicaciones de App Engine, intenta implementar una aplicación de muestra o sigue un instructivo antes de continuar.

  1. Configura la aplicación
    Crea el archivo de configuración app.yaml para especificar la aplicación cliente que controla los eventos de notificación de cambio del depósito.
    application: <ApplicationId>
    version: 1
    runtime: python27
    api_version: 1
    threadsafe: true
    
    handlers:
    - url: /.*
      script: change_notification_client.app
    

  2. Crea la aplicación
    En el ejemplo siguiente, se implementa una aplicación cliente para controlar los eventos de notificación de cambio de un depósito. Asígnale el nombre change_notification_client.py y, luego, implementa tu aplicación:

    """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. Asigna el permiso de acceso de la aplicación al depósito
    Si tu depósito pertenece a una cuenta de servicio diferente a la de tu aplicación de App Engine, otorga a la aplicación acceso de PROPIETARIO al depósito mediante la ejecución del comando siguiente:
    gsutil acl ch -u ApplicationId@appspot.gserviceaccount.com:OWNER gs://BucketName
    
  4. Comienza a observar el depósito en busca de cambios de objetos
    Crea un canal de notificación para tu aplicación mediante la observación del depósito con gsutil:
    gsutil notification watchbucket ApplicationUrl gs://BucketName
    
    donde ApplicationUrl es la URL de tu aplicación de App Engine, por ejemplo, https://ApplicationId.appspot.com/.
  5. Prueba la aplicación
    Para comprobar si la aplicación funciona como se esperaba, realiza los pasos siguientes:
    1. Para asegurarte de que la aplicación se haya implementado y funcione correctamente, ejecuta el siguiente comando curl:
      curl -X Post https://<ApplicationId>.appspot.com
      
      Si usaste tu propio nombre de dominio para implementar la aplicación, úsalo en lugar de appspot.com en el comando anterior.
    2. Ve a la página Registro de tu proyecto. Actualiza la lista de los mensajes registrados, si es necesario. Verifica que el mensaje de registro que emite la aplicación esté registrado.
    3. Agrega un objeto al depósito. Puedes usar la herramienta de gsutil del siguiente modo:
      gsutil cp ObjectName gs://BucketName/
      
      Cloud Storage notifica a la aplicación, que luego registra un mensaje.
    4. Ve a la página Registro de tu proyecto. Actualiza la lista de los mensajes registrados y busca el mensaje para la copia del objeto.
    5. </ol>
      

    6. Quita el canal de notificación
      Puedes quitar el canal de notificación si especificas los identificadores del canal y de los recursos que se mostraron cuando emitiste el comando de notificación para observar el depósito.
      gsutil notification stopchannel <channel_id> <resource_identifier>