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 bucket.

¿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 buckets 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 para configurar las notificaciones de Pub/Sub en Cloud Storage, consulta Configura las notificaciones de Pub/Sub en Cloud Storage.

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 bucket 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 bucket. 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 bucket. Por ejemplo, cuando agregas una foto nueva a un bucket, se puede notificar a una aplicación a fin de crear una miniatura.

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 esta debe ser 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 bucket específico, es decir, si existen varios canales de notificación para un solo bucket, 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 bucket

Para comenzar a observar un bucket para los eventos de notificación de cambio, realiza una solicitud watchAll. Esto crea un canal de notificaciones que envía los eventos de notificaciones a la address determinada para el bucket en particular. El canal de notificaciones incluye un token cliente personalizado y un identificador de canal, si se especifica.

Esta es una solicitud POST de ejemplo para observar un 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"
}

Autorización de notificación

Cuando se observa un bucket, el canal de notificación que se crea estará asociado al proyecto de la consola de Google Cloud 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 bucket que se observa.

Dado que una cuenta de servicio está asociada a un proyecto, si la usas para observar un bucket, creará un canal de notificaciones en el proyecto de la cuenta de servicio.

Quita un canal de notificación

Para detener un canal de notificaciones, realiza una solicitud stop. Esto detiene todos los eventos de notificaciones del identificador de recursos especificado (resourceId) y la sincronización del identificador de canal (id). Los canales activos adicionales para el mismo recurso no se ven 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.

Esta es una solicitud POST de ejemplo 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

Sincronización

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 bucket se enviarán a la URL de la aplicación configurada para el canal.

La notificación se enviará como una solicitud POST a la URL de la aplicación configurada. La solicitud no tiene cuerpo. Los metadatos de notificación de sincronización se encuentran en los encabezados de la solicitud. El siguiente es un ejemplo de la solicitud de notificación de sincronización:

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

Adición, actualización o eliminación de objetos

Se envía un evento de notificación cuando se agrega un objeto nuevo a un bucket, cuando se modifica el contenido o los metadatos de un objeto existente o cuando se borra un objeto de un bucket.

La notificación se enviará como una solicitud POST a la URL de la aplicación configurada. El cuerpo de la solicitud contiene un mensaje codificado en JSON, como se muestra en la siguiente solicitud de notificación:

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://content-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:
  • exists: para adiciones y actualizaciones de objetos
  • not_exists: para la eliminación de objetos

y donde el contenido del mensaje de JSON incluya la representación actual del objeto como se describe en 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 tu aplicación puede que no esté siempre disponible, se siguen las reglas siguientes cuando se envían las 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.

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: APPLICATION
    version: 1
    runtime: python38
    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 bucket pertenece a una cuenta de servicio diferente a la de tu aplicación de App Engine, otórgale a la aplicación acceso de PROPIETARIO al bucket.
  4. Comienza a observar el depósito en busca de cambios de objetos
    Para crear un canal de notificaciones para tu aplicación, observa el bucket con una solicitud watchAll con el address de la URL para tu aplicación de App Engine, p. ej., 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://APPLICATION_ID.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 envía la aplicación esté registrado.
    3. Agrega un objeto al bucket. 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.
  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 bucket.