En Servicio de eventos Couchbase le permite actuar rápidamente en caso de mutaciones (o cambios) en sus datos. Todas las acciones en Eventos se llevan a cabo mediante la ejecución de una lambda, un pequeño fragmento de lógica de negocio escrito en JavaScript.

Entre los casos de uso más comunes se incluyen el enriquecimiento de datos, el archivo de documentos y la integración con servicios REST externos. Más información aquí.

En el siguiente blog, describiremos cómo se pueden manejar los errores durante la ejecución del listador de eventos. Mediante el uso de un mecanismo de reintento nos aseguramos de que la acción prevista se lleva a cabo, incluso si el receptor de eventos falla durante la ejecución.

Ejemplo de solicitud

Como ejemplo, implementamos parte de una aplicación de comercio electrónico que almacena los pedidos de los clientes en una colección de Couchbase. En cuanto el estado de un pedido cambia a pagadoQueremos enviar una confirmación de pedido al cliente.

Para lograrlo, integramos un receptor de eventos de Couchbase con una aplicación externa servicio de correo electrónico. El receptor de eventos de Couchbase recogerá cualquier cambio en el documento del pedido, verificará que el pedido se ha pagado y, a continuación, llamará al servicio de correo electrónico para activar el mensaje de confirmación.

El servicio de correo electrónico es un microservicio independiente que proporciona un punto final REST. Usamos el soporte cURL integrado directamente en Couchbase Eventing para llamar al microservicio desde el receptor de eventos.

Flujo conceptual: A medida que los pedidos se actualizan en Couchbase, los eventos se disparan y son recogidos por un listener de eventos. A continuación, el receptor de eventos llama al servicio de correo electrónico externo.

 El servicio de correo electrónico devuelve un error

El escenario descrito funciona muy bien si el servicio de correo electrónico está operativo. Sin embargo, ¿qué ocurre si el servicio de correo electrónico devuelve un error? Las peticiones del escuchador de eventos al servicio de correo electrónico fallarán y, por tanto, no se enviará ningún mensaje de confirmación al cliente. Dado que en el momento del fallo el evento de cambio de documento de Couchbase ya ha sido procesado, no se dispara ningún nuevo evento para el mismo documento a menos que haya otro cambio en él. Para asegurar que la confirmación es enviada necesitamos manejar el error e implementar un mecanismo de reintento. Haciendo esto podemos solucionar cualquier problema temporal del servicio externo y al mismo tiempo garantizar que la confirmación es enviada.

 Hay diferentes maneras de enfocar esto. En mi ejemplo de abajo elijo crear una nueva colección llamada 'retry', que almacenará referencias a los documentos para los que falló la ejecución del listener de eventos.

 El receptor de eventos recogerá los cambios en los documentos de pedido (paso #1) y luego llamará al servicio de correo electrónico (paso #2). Si la llamada al servicio de correo electrónico tiene éxito, el receptor de eventos actualiza el estado del mensaje de confirmación en el documento de pedido (paso #3). Sin embargo, en caso de fallo, se crea un documento de reintento y se coloca en la colección "reintento" (paso #3*).

Mantener una referencia a los documentos nos permite identificar todas las actualizaciones fallidas y nos permite volver a ejecutarlas más tarde. Esto podría ser mediante la intervención manual de un operador o el reintento automático utilizando temporizadores de eventos de Couchbase.

  1. Iniciamos el proceso de reintento añadiendo un documento con un id de documento especificado a la colección de reintentos. Se crea un temporizador recurrente con un intervalo proporcionado.
  2. En la ejecución del temporizador, todos los documentos más antiguos que un pequeño cuanto de tiempo en el reintentar se actualizan. Añadiendo un atributo como fireRetry = true a los documentos de reintento disparamos otro evento de actualización que es recogido por el escuchador de eventos para ejecutar el mecanismo de reintento. Esto nos da una mutación recursiva que enciende todos los documentos de la colección retry en paralelo. La función de reintento se ejecuta ahora utilizando todos los hilos de trabajo disponibles en paralelo.
  3. Se activa un evento de actualización de documento para cada documento de reintento individualmente.
  4. El documento de pedido correspondiente se recupera de la colección de entrada
  5. Ahora se llama al servicio de correo electrónico.
  6. Si la llamada al servicio de correo electrónico tiene éxito, el receptor de eventos actualiza el estado del mensaje de confirmación en el documento de pedido y elimina el documento de reintento. 
  7. En caso de fallo, el documento de reintento se actualiza y se coloca en la colección "reintento".

Revisión de códigos

 Ahora que ya hemos establecido el diseño conceptual, echemos un vistazo al ejemplo de implementación:

Requisitos previos:

  • Couchbase 7 Enterprise Edition. Ejecuto Couchbase como un clúster de nodo único en Docker en mi máquina local. (https://docs.couchbase.com/server/current/install/getting-started-docker.html)
  • Para propósitos de desarrollo creamos un Cluster Couchbase de un solo nodo ejecutando los siguientes servicios:
    • Índices, consultas, eventos y servicios de datos

Tenga en cuenta que no se recomienda la instalación en un único nodo para su uso en producción.

Preparación

  • Crear un cubo llamado pedidos
  • Cree dos colecciones en pedidos cubos _ámbito por defecto:
    • entrada (contendrá todos los pedidos entrantes)
    • reintentar (contendrá los documentos de reintento referidos a las órdenes que han fallado)

  • Crear cubo metadatos. Utilizaremos el ámbito _default y la colección _default. El bucket de metadatos se utiliza para los metadatos de Eventing.

  • Crear un índice en reintentar colección. El retry listener consultará cualquier documento contenido en la colección utilizando N1QL, por lo que es necesario que exista un índice para que se ejecute la consulta.

 Documento de pedido de modelo de datos

Para esta aplicación de ejemplo, utilizamos un modelo de datos ligero para el documento de pedido, que sólo contiene los campos relevantes. Se omiten muchos otros campos que normalmente se esperarían en un documento de pedido.

Documento de reintento de modelo de datos

El documento de reintento contiene algunos atributos básicos, como el identificador del documento de pedido, un contador de intentos y una marca de tiempo. La dirección tipo  no es necesario en nuestra aplicación, pero puede ser útil para determinar el tipo de notificación por correo electrónico en caso de que la aplicación se amplíe para enviar también actualizaciones de envío y entrega.

Servicio de correo electrónico MOCK 

Simularemos el Servicio de Correo Electrónico utilizando un simple script Python ejecutando un servidor web local. El script responderá aleatoriamente con HTTP 200 OK, o con HTTP 406 para indicar un fallo.

  1. Actualice la dirección IP a la dirección IP de su máquina local en la línea 31servidor = ThreadedHTTPServer(('sustituir por su IP', 9080), Handler)
  2. Inicie el script ejecutando: python http.py

Receptores de eventos

Ahora con todos los preparativos en su lugar podemos seguir adelante y añadir los dos oyentes de eventos:

  • evt_send_confirmation_email - proporciona la integración con el Servicio de Correo Electrónico
  • evt_send_confirmation_email_retry - contiene la lógica de reintento
  1. Los oyentes están disponibles aquí: https://github.com/puhhma/cb_eventing_retry_sample
  2. Importe los oyentes (json ) en el servicio Couchbase Eventing.

Ten en cuenta que, para que funcionen, debes seguir las convenciones de nomenclatura utilizadas en este artículo. 

Consulte evt_send_confirmation_email oyente

Configuración del receptor de eventos:

  • El receptor de eventos está escuchando el evento entrada colección en el pedidos cubo.
  • En metadatos bucket se utiliza para almacenar los metadatos de los oyentes
  • Los alias de los cubos bkt_order_inbound y bkt_order_retry hacer referencia al entrada y reintentar colección en el pedir cubo
  • En curlServicioCorreoHost especifica el alias de URL para el mock EmailService. Por favor, asegúrese de actualizar con su dirección IP

 

  • Para más detalles, consulte los comentarios en línea
  • En OnUpdate se activa cuando se actualiza o se crea un documento de pedido
  • La solicitud se construye y la solicitud HTTP POST se envía al EmailService utilizando cURL.
  • Se evalúa el resultado. En caso de que la respuesta HTTP no sea satisfactoria, se construye un documento de reintento y se añade al archivo reintentar colección.

  • El receptor de eventos está escuchando el evento reintentar colección en el pedidos cubo.
  • En metadatos bucket se utiliza para almacenar los metadatos de los oyentes
  • Los alias de los cubos bkt_order_inbound y bkt_order_retry hacer referencia al entrada y reintentar en la cubeta de pedidos
  • En curlServicioCorreoHost especifica el alias de URL para el mock EmailService
  • En retryTimerIntervall especifica el intervalo del temporizador en segundos.

 

  • El temporizador se inicia añadiendo un documento con el id allow_retrys a la reintentar colección
  • A continuación, el temporizador se inicializa y la función RetryTimerCallback asociada al temporizador
  • Una vez ejecutado el temporizador se llama a la función RetryTimerCallback
  • Antes de proceder con el mecanismo de reintento, se crea un nuevo temporizador como primer paso para garantizar que sigue funcionando en caso de errores posteriores.
  • Se utiliza una consulta N1QL para actualizar todos los reintentar documentos en el reintentar añadiendo un fireRetry al documento
  • Cada cambio de documento da lugar a un evento de actualización del documento y se ejecuta el mecanismo de reintento
  • El documento de pedido se resuelve a partir del entrada y el EmailService se llama a través de cURL
  • En caso de fallo, el reintentar y se actualiza el documento intente contador aumentado

Probar la aplicación de ejemplo

Ahora es el momento de probar finalmente la aplicación de ejemplo:

  1. Asegúrese de que el mock EmailService está en funcionamiento
  2. Inicie el evt_send_confirmation_email pero manteniendo el evt_send_confirmation_email_retry oyente se detuvo por ahora.
  3. Cree un documento de pedido de muestra (véase el modelo de datos anterior) en la consola de Couchbase
  4. En caso de respuesta positiva, el confirmationEmailEnviado se actualiza a true en el atributo pedir documento.
  5. En caso de fallo, se crea un documento de reintento en la carpeta reintentar recogida. Dado que el EmailService responderá aleatoriamente con un error, repita el paso #3 hasta que se produzca un error.
  6. Ahora que hemos capturado un error, vamos a iniciar el escuchador de eventos de reintento evt_send_confirmation_email_retry
  7. Crea un documento con el id 'allow_retrys'. Esto inicializará el mecanismo de reintentos.
  8. Al cabo de unos instantes, el oyente se activará y empezará a procesar los documentos de la base de datos. reintentar colección.
  9. Por favor, observe que el atributo 'attempt' se incrementa con cada actualización fallida del Servicio de Correo Electrónico. En caso de éxito, el documento de pedido se actualiza y el atributo reintentar documento retirado del reintentar colección.

Dado que la respuesta del Email Service Mock es aleatoria, es posible que tenga que repetir los pasos anteriores para poder observar el comportamiento previsto.

Conclusión

En este artículo esbozo un mecanismo de reintento para manejar condiciones de error al integrar Couchbase Eventing con un servicio REST externo. Esta o soluciones similares se pueden utilizar para garantizar que las acciones previstas se lleven a cabo incluso si el servicio externo está temporalmente funcionando mal. 

A la hora de considerar un mecanismo de reintentos hay que tener en cuenta varios factores, como el volumen de reintentos, los hilos de trabajo disponibles para Couchbase Eventing y las peticiones que el servicio externo puede gestionar.

Puedes encontrar más información sobre el funcionamiento interno de Couchbase Eventing aquí: https://docs.couchbase.com/server/current/eventing/eventing-overview.html

Muchas gracias a Jon Strabala (Principal Product Manager, Couchbase) por sus conocimientos técnicos y su ayuda con este artículo.

Autor

Publicado por Marian Puhl, Ingeniera de soluciones

Marian Puhl es ingeniera de soluciones de Couchbase en la región nórdica.

Dejar una respuesta