{"id":12471,"date":"2021-11-15T10:34:56","date_gmt":"2021-11-15T18:34:56","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=12471"},"modified":"2025-06-13T22:39:19","modified_gmt":"2025-06-14T05:39:19","slug":"couchbase-eventing-handling-errors-and-retries","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/es\/couchbase-eventing-handling-errors-and-retries\/","title":{"rendered":"Couchbase Eventing Manejo de Errores y Reintentos"},"content":{"rendered":"<p><span style=\"font-weight: 400\">En <\/span><a href=\"https:\/\/docs.couchbase.com\/server\/current\/eventing\/eventing-overview.html\"><span style=\"font-weight: 400\">Servicio de eventos Couchbase<\/span><\/a><span style=\"font-weight: 400\"> le permite actuar r\u00e1pidamente en caso de mutaciones (o cambios) en sus datos. Todas las acciones en <a href=\"https:\/\/www.couchbase.com\/blog\/es\/products\/eventing\/\">Eventos<\/a> se llevan a cabo mediante la ejecuci\u00f3n de una lambda, un peque\u00f1o fragmento de l\u00f3gica de negocio escrito en JavaScript.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Entre los casos de uso m\u00e1s comunes se incluyen el enriquecimiento de datos, el archivo de documentos y la integraci\u00f3n con servicios REST externos. M\u00e1s informaci\u00f3n <\/span><a href=\"https:\/\/docs.couchbase.com\/server\/current\/eventing\/eventing-examples.html\"><span style=\"font-weight: 400\">aqu\u00ed<\/span><\/a><span style=\"font-weight: 400\">.<\/span><\/p>\n<p><span style=\"font-weight: 400\">En el siguiente blog, describiremos c\u00f3mo se pueden manejar los errores durante la ejecuci\u00f3n del listador de eventos. Mediante el uso de un mecanismo de reintento nos aseguramos de que la acci\u00f3n prevista se lleva a cabo, incluso si el receptor de eventos falla durante la ejecuci\u00f3n.<\/span><\/p>\n<p><b><i>Ejemplo de solicitud<\/i><\/b><\/p>\n<p><span style=\"font-weight: 400\">Como ejemplo, implementamos parte de una aplicaci\u00f3n de comercio electr\u00f3nico que almacena los pedidos de los clientes en una colecci\u00f3n de Couchbase. En cuanto el estado de un pedido cambia a <\/span><b>pagado<\/b><span style=\"font-weight: 400\">Queremos enviar una confirmaci\u00f3n de pedido al cliente.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Para lograrlo, integramos un receptor de eventos de Couchbase con una aplicaci\u00f3n externa <\/span><i><span style=\"font-weight: 400\">servicio de correo electr\u00f3nico<\/span><\/i><span style=\"font-weight: 400\">. El receptor de eventos de Couchbase recoger\u00e1 cualquier cambio en el documento del pedido, verificar\u00e1 que el pedido se ha pagado y, a continuaci\u00f3n, llamar\u00e1 al servicio de correo electr\u00f3nico para activar el mensaje de confirmaci\u00f3n.<\/span><\/p>\n<p><span style=\"font-weight: 400\">El servicio de correo electr\u00f3nico 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.<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-12458 size-large\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2021\/11\/Screen-Shot-2021-11-10-at-22.37.22-1024x352.png\" alt=\"\" width=\"900\" height=\"309\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/Screen-Shot-2021-11-10-at-22.37.22-1024x352.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/Screen-Shot-2021-11-10-at-22.37.22-300x103.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/Screen-Shot-2021-11-10-at-22.37.22-768x264.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/Screen-Shot-2021-11-10-at-22.37.22-1536x529.png 1536w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/Screen-Shot-2021-11-10-at-22.37.22-2048x705.png 2048w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/Screen-Shot-2021-11-10-at-22.37.22-20x7.png 20w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/Screen-Shot-2021-11-10-at-22.37.22-1320x454.png 1320w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/p>\n<p><i><span style=\"font-weight: 400\">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\u00f3n, el receptor de eventos llama al servicio de correo electr\u00f3nico externo.<\/span><\/i><\/p>\n<p><span style=\"font-weight: 400\">\u00a0<\/span><b>El servicio de correo electr\u00f3nico devuelve un error<\/b><\/p>\n<p><span style=\"font-weight: 400\">El escenario descrito funciona muy bien si el <\/span><i><span style=\"font-weight: 400\">servicio de correo electr\u00f3nico<\/span><\/i><span style=\"font-weight: 400\"> est\u00e1 operativo. Sin embargo, \u00bfqu\u00e9 ocurre si el <\/span><i><span style=\"font-weight: 400\">servicio de correo electr\u00f3nico<\/span><\/i><span style=\"font-weight: 400\"> devuelve un error? Las peticiones del escuchador de eventos al servicio de correo electr\u00f3nico fallar\u00e1n y, por tanto, no se enviar\u00e1 ning\u00fan mensaje de confirmaci\u00f3n 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\u00fan nuevo evento para el mismo documento a menos que haya otro cambio en \u00e9l. Para asegurar que la confirmaci\u00f3n 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\u00f3n es enviada.<\/span><\/p>\n<p><span style=\"font-weight: 400\">\u00a0<\/span><span style=\"font-weight: 400\">Hay diferentes maneras de enfocar esto. En mi ejemplo de abajo elijo crear una nueva colecci\u00f3n llamada 'retry', que almacenar\u00e1 referencias a los documentos para los que fall\u00f3 la ejecuci\u00f3n del listener de eventos.<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-12459 size-large\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2021\/11\/Screen-Shot-2021-11-10-at-22.39.25-1024x435.png\" alt=\"\" width=\"900\" height=\"382\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/Screen-Shot-2021-11-10-at-22.39.25-1024x435.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/Screen-Shot-2021-11-10-at-22.39.25-300x127.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/Screen-Shot-2021-11-10-at-22.39.25-768x326.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/Screen-Shot-2021-11-10-at-22.39.25-1536x652.png 1536w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/Screen-Shot-2021-11-10-at-22.39.25-2048x869.png 2048w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/Screen-Shot-2021-11-10-at-22.39.25-20x8.png 20w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/Screen-Shot-2021-11-10-at-22.39.25-1320x560.png 1320w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/p>\n<p><span style=\"font-weight: 400\">\u00a0<\/span><span style=\"font-weight: 400\">El receptor de eventos recoger\u00e1 los cambios en los documentos de pedido (paso #1) y luego llamar\u00e1 al servicio de correo electr\u00f3nico (paso #2). Si la llamada al servicio de correo electr\u00f3nico tiene \u00e9xito, el receptor de eventos actualiza el estado del mensaje de confirmaci\u00f3n 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\u00f3n \"reintento\" (paso #3*).<\/span><\/p>\n<p><span style=\"font-weight: 400\">Mantener una referencia a los documentos nos permite identificar todas las actualizaciones fallidas y nos permite volver a ejecutarlas m\u00e1s tarde. Esto podr\u00eda ser mediante la intervenci\u00f3n manual de un operador o el reintento autom\u00e1tico utilizando temporizadores de eventos de Couchbase.<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-12460 size-large\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2021\/11\/Screen-Shot-2021-11-10-at-22.40.24-1024x435.png\" alt=\"\" width=\"900\" height=\"382\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/Screen-Shot-2021-11-10-at-22.40.24-1024x435.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/Screen-Shot-2021-11-10-at-22.40.24-300x127.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/Screen-Shot-2021-11-10-at-22.40.24-768x326.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/Screen-Shot-2021-11-10-at-22.40.24-1536x652.png 1536w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/Screen-Shot-2021-11-10-at-22.40.24-2048x869.png 2048w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/Screen-Shot-2021-11-10-at-22.40.24-20x8.png 20w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/Screen-Shot-2021-11-10-at-22.40.24-1320x560.png 1320w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/p>\n<ol>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Iniciamos el proceso de reintento a\u00f1adiendo un documento con un id de documento especificado a la colecci\u00f3n de reintentos. Se crea un temporizador recurrente con un intervalo proporcionado.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">En la ejecuci\u00f3n del temporizador, todos los documentos m\u00e1s antiguos que un peque\u00f1o cuanto de tiempo en el <\/span><i><span style=\"font-weight: 400\">reintentar<\/span><\/i><span style=\"font-weight: 400\"> se actualizan. A\u00f1adiendo un atributo como <\/span><i><span style=\"font-weight: 400\">fireRetry = true<\/span><\/i><span style=\"font-weight: 400\"> a los documentos de reintento disparamos otro evento de actualizaci\u00f3n que es recogido por el escuchador de eventos para ejecutar el mecanismo de reintento. Esto nos da una mutaci\u00f3n recursiva que enciende todos los documentos de la colecci\u00f3n retry en paralelo. La funci\u00f3n de reintento se ejecuta ahora utilizando todos los hilos de trabajo disponibles en paralelo.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Se activa un evento de actualizaci\u00f3n de documento para cada documento de reintento individualmente.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">El documento de pedido correspondiente se recupera de la colecci\u00f3n de entrada<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Ahora se llama al servicio de correo electr\u00f3nico.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Si la llamada al servicio de correo electr\u00f3nico tiene \u00e9xito, el receptor de eventos actualiza el estado del mensaje de confirmaci\u00f3n en el documento de pedido y elimina el documento de reintento.\u00a0<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">En caso de fallo, el documento de reintento se actualiza y se coloca en la colecci\u00f3n \"reintento\".<\/span><\/li>\n<\/ol>\n<p><b>Revisi\u00f3n de c\u00f3digos<\/b><\/p>\n<p><span style=\"font-weight: 400\">\u00a0<\/span><span style=\"font-weight: 400\">Ahora que ya hemos establecido el dise\u00f1o conceptual, echemos un vistazo al ejemplo de implementaci\u00f3n:<\/span><\/p>\n<p><b>Requisitos previos<\/b><span style=\"font-weight: 400\">:<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Couchbase 7 Enterprise Edition. Ejecuto Couchbase como un cl\u00faster de nodo \u00fanico en Docker en mi m\u00e1quina local. (https:\/\/docs.couchbase.com\/server\/current\/install\/getting-started-docker.html)<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Para prop\u00f3sitos de desarrollo creamos un Cluster Couchbase de un solo nodo ejecutando los siguientes servicios:<\/span>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">\u00cdndices, consultas, eventos y servicios de datos<\/span><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><span style=\"font-weight: 400\">Tenga en cuenta que no se recomienda la instalaci\u00f3n en un \u00fanico nodo para su uso en producci\u00f3n.<\/span><\/p>\n<p><b>Preparaci\u00f3n<\/b><\/p>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Crear un cubo llamado <\/span><b><i>pedidos<\/i><\/b><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Cree dos colecciones en <\/span><b><i>pedidos<\/i><\/b><span style=\"font-weight: 400\"> cubos _\u00e1mbito por defecto:<\/span>\n<ul>\n<li style=\"font-weight: 400\"><b>entrada<\/b><span style=\"font-weight: 400\"> (contendr\u00e1 todos los pedidos entrantes)<\/span><\/li>\n<li style=\"font-weight: 400\"><b>reintentar<\/b><span style=\"font-weight: 400\"> (contendr\u00e1 los documentos de reintento referidos a las \u00f3rdenes que han fallado)<\/span><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-12461 size-large\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2021\/11\/eventing1-1024x331.png\" alt=\"\" width=\"900\" height=\"291\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/eventing1-1024x331.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/eventing1-300x97.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/eventing1-768x248.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/eventing1-1536x496.png 1536w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/eventing1-20x6.png 20w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/eventing1-1320x427.png 1320w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/eventing1.png 1600w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/p>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Crear cubo <\/span><b>metadatos<\/b><span style=\"font-weight: 400\">. Utilizaremos el \u00e1mbito _default y la colecci\u00f3n _default. El bucket de metadatos se utiliza para los metadatos de Eventing.<\/span><\/li>\n<\/ul>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-12462 size-large\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2021\/11\/eventing2-1024x226.png\" alt=\"\" width=\"900\" height=\"199\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/eventing2-1024x226.png 1024w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/eventing2-300x66.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/eventing2-768x169.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/eventing2-1536x339.png 1536w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/eventing2-20x4.png 20w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/eventing2-1320x291.png 1320w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/eventing2.png 1600w\" sizes=\"auto, (max-width: 900px) 100vw, 900px\" \/><\/p>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Crear un \u00edndice en <\/span><i><span style=\"font-weight: 400\">reintentar<\/span><\/i><span style=\"font-weight: 400\"> colecci\u00f3n. El retry listener consultar\u00e1 cualquier documento contenido en la colecci\u00f3n utilizando N1QL, por lo que es necesario que exista un \u00edndice para que se ejecute la consulta.<\/span><\/li>\n<\/ul>\n<pre class=\"lang:default decode:true\">CREATE PRIMARY INDEX idx_default_primary ON orders._default.retry USING GSI;<\/pre>\n<p><span style=\"font-weight: 400\">\u00a0<\/span><b><i>Documento de pedido de modelo de datos<\/i><\/b><\/p>\n<p><span style=\"font-weight: 400\">Para esta aplicaci\u00f3n de ejemplo, utilizamos un modelo de datos ligero para el documento de pedido, que s\u00f3lo contiene los campos relevantes. Se omiten muchos otros campos que normalmente se esperar\u00edan en un documento de pedido.<\/span><\/p>\n<pre class=\"lang:default decode:true\">{\r\n\u00a0\u00a0\"email\": \"customer_email\",\r\n\u00a0\u00a0\"paymentStatus\": \"initiated\",\r\n\u00a0\u00a0\"confirmationEmailSent\": false,\r\n\u00a0\u00a0\"items\": [\r\n\u00a0\u00a0\u00a0\u00a0{\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"name\": \"Swedish Meatballs 500g\",\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"amount\": 2,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"unitPrice\": 9.95\r\n\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0]\r\n}<\/pre>\n<p><b><i>Documento de reintento de modelo de datos<\/i><\/b><\/p>\n<p><span style=\"font-weight: 400\">El documento de reintento contiene algunos atributos b\u00e1sicos, como el identificador del documento de pedido, un contador de intentos y una marca de tiempo. La direcci\u00f3n <\/span><i><span style=\"font-weight: 400\">tipo <\/span><\/i><span style=\"font-weight: 400\">\u00a0no es necesario en nuestra aplicaci\u00f3n, pero puede ser \u00fatil para determinar el tipo de notificaci\u00f3n por correo electr\u00f3nico en caso de que la aplicaci\u00f3n se ampl\u00ede para enviar tambi\u00e9n actualizaciones de env\u00edo y entrega.<\/span><\/p>\n<pre class=\"lang:default decode:true\">{\r\n\u00a0\u00a0\"type\": \"confirmation\",\r\n\u00a0\u00a0\"docId\": \"order_140\",\r\n\u00a0\u00a0\"attempt\": 1,\r\n\u00a0\u00a0\"ts\": 1632775908319\r\n}<\/pre>\n<p><b><i>Servicio de correo electr\u00f3nico MOCK\u00a0<\/i><\/b><\/p>\n<p><span style=\"font-weight: 400\">Simularemos el Servicio de Correo Electr\u00f3nico utilizando un simple script Python ejecutando un servidor web local. El script responder\u00e1 aleatoriamente con HTTP 200 OK, o con HTTP 406 para indicar un fallo.<\/span><\/p>\n<ol>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Actualice la direcci\u00f3n IP a la direcci\u00f3n IP de su m\u00e1quina local en la l\u00ednea 31<\/span><em>servidor = ThreadedHTTPServer(('sustituir por su IP', 9080), Handler)<\/em><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Inicie el script ejecutando: python http.py<\/span><\/li>\n<\/ol>\n<p><b>Receptores de eventos<\/b><\/p>\n<p><span style=\"font-weight: 400\">Ahora con todos los preparativos en su lugar podemos seguir adelante y a\u00f1adir los dos oyentes de eventos:<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400\"><b>evt_send_confirmation_email<\/b><span style=\"font-weight: 400\"> - proporciona la integraci\u00f3n con el Servicio de Correo Electr\u00f3nico<\/span><\/li>\n<li style=\"font-weight: 400\"><b>evt_send_confirmation_email_retry<\/b><span style=\"font-weight: 400\"> - contiene la l\u00f3gica de reintento<\/span><\/li>\n<\/ul>\n<ol>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Los oyentes est\u00e1n disponibles aqu\u00ed: https:\/\/github.com\/puhhma\/cb_eventing_retry_sample<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Importe los oyentes (<\/span><i><span style=\"font-weight: 400\">json<\/span><\/i><span style=\"font-weight: 400\"> ) en el servicio Couchbase Eventing.<\/span><\/li>\n<\/ol>\n<p><span style=\"font-weight: 400\">Ten en cuenta que, para que funcionen, debes seguir las convenciones de nomenclatura utilizadas en este art\u00edculo.\u00a0<\/span><\/p>\n<p><b>Consulte <\/b><b><i>evt_send_confirmation_email<\/i><\/b><b> oyente<\/b><\/p>\n<p><span style=\"font-weight: 400\">Configuraci\u00f3n del receptor de eventos:<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-12465 size-large\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2021\/11\/function-1-602x1024.png\" alt=\"\" width=\"602\" height=\"1024\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/function-1-602x1024.png 602w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/function-1-176x300.png 176w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/function-1-768x1307.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/function-1-902x1536.png 902w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/function-1-300x511.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/function-1-12x20.png 12w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/function-1.png 940w\" sizes=\"auto, (max-width: 602px) 100vw, 602px\" \/><\/p>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">El receptor de eventos est\u00e1 escuchando el evento <\/span><i><span style=\"font-weight: 400\">entrada<\/span><\/i><span style=\"font-weight: 400\"> colecci\u00f3n en el <\/span><i><span style=\"font-weight: 400\">pedidos<\/span><\/i><span style=\"font-weight: 400\"> cubo.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">En <\/span><i><span style=\"font-weight: 400\">metadatos<\/span><\/i><span style=\"font-weight: 400\"> bucket se utiliza para almacenar los metadatos de los oyentes<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Los alias de los cubos <\/span><i><span style=\"font-weight: 400\">bkt_order_inbound<\/span><\/i><span style=\"font-weight: 400\"> y <\/span><i><span style=\"font-weight: 400\">bkt_order_retry<\/span><\/i><span style=\"font-weight: 400\"> hacer referencia al <\/span><i><span style=\"font-weight: 400\">entrada<\/span><\/i><span style=\"font-weight: 400\"> y <\/span><i><span style=\"font-weight: 400\">reintentar<\/span><\/i><span style=\"font-weight: 400\"> colecci\u00f3n en el <\/span><i><span style=\"font-weight: 400\">pedir<\/span><\/i><span style=\"font-weight: 400\"> cubo<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">En <\/span><i><span style=\"font-weight: 400\">curlServicioCorreoHost<\/span><\/i><span style=\"font-weight: 400\"> especifica el alias de URL para el mock EmailService. Por favor, aseg\u00farese de actualizar con su direcci\u00f3n IP<\/span><\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<pre class=\"lang:default decode:true\">\/\/ OnUpdate is invoked for all documents created\/updated in the 'inbound' bucket\r\nfunction OnUpdate(doc, meta) {\r\n\u00a0\u00a0\u00a0\u00a0\/\/ determine if document status is 'paid' &amp; confirmation email was not previously sent\r\n\u00a0\u00a0\u00a0\u00a0if( doc.paymentStatus === \"paid\" &amp;&amp; !doc.confirmationEmailSent ) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0SendConfirmationMail(doc, meta.id);\r\n\u00a0\u00a0\u00a0\u00a0} else {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if (debug_level &gt; 1)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0log(\"Nothing to do for: \" + meta.id);\r\n\u00a0\u00a0\u00a0\u00a0}\r\n}\r\n\r\nfunction SendConfirmationMail(doc, docId) {\r\n\u00a0\u00a0try {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/ build the request to the EmailService\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0var request = {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0path: 'sendConfirmation',\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0body: doc\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0};\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/\u00a0 perform the cURL request using the URL alias 'curlEmailServiceHost' from the settings\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0var response = curl('POST', curlEmailServiceHost, request);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if (response.status != 200) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/ this did not work as expected\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if (debug_level &gt; 1) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0log(\"docId\", docId, \"cURL POST failed response.status:\",response.status);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/ create retry document referencing the documentId and store in 'retry' bucket\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0bkt_order_retry[docId] = {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"docId\": docId,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"attempt\": 1,\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\"ts\": Date.now()\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0} else {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if (debug_level &gt; 5) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0log(\"cURL POST success, sent\",docId,\"response.body:\",response.body);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/ update confirmationEmailSent status\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0doc.confirmationEmailSent = true;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0bkt_order_inbound[docId] = doc;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0} catch (e) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0log(\"ERROR cURL request had an exception:\",e)\r\n\u00a0\u00a0}\r\n}<\/pre>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Para m\u00e1s detalles, consulte los comentarios en l\u00ednea<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">En <\/span><i><span style=\"font-weight: 400\">OnUpdate <\/span><\/i><span style=\"font-weight: 400\">se activa cuando se actualiza o se crea un documento de pedido<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">La solicitud se construye y la solicitud HTTP POST se env\u00eda al EmailService utilizando cURL.<\/span><\/li>\n<li style=\"font-weight: 400\">Se eval\u00faa el resultado. En caso de que la respuesta HTTP no sea satisfactoria, se construye un documento de reintento y se a\u00f1ade al archivo <i>reintentar<\/i> colecci\u00f3n.<\/li>\n<\/ul>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-12464 size-large\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2021\/11\/function-564x1024.png\" alt=\"\" width=\"564\" height=\"1024\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/function-564x1024.png 564w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/function-165x300.png 165w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/function-768x1393.png 768w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/function-847x1536.png 847w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/function-300x544.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/function-11x20.png 11w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/function.png 882w\" sizes=\"auto, (max-width: 564px) 100vw, 564px\" \/><\/p>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">El receptor de eventos est\u00e1 escuchando el evento <\/span><i><span style=\"font-weight: 400\">reintentar<\/span><\/i><span style=\"font-weight: 400\"> colecci\u00f3n en el <\/span><i><span style=\"font-weight: 400\">pedidos<\/span><\/i><span style=\"font-weight: 400\"> cubo.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">En <\/span><i><span style=\"font-weight: 400\">metadatos<\/span><\/i><span style=\"font-weight: 400\"> bucket se utiliza para almacenar los metadatos de los oyentes<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Los alias de los cubos <\/span><i><span style=\"font-weight: 400\">bkt_order_inbound<\/span><\/i><span style=\"font-weight: 400\"> y <\/span><i><span style=\"font-weight: 400\">bkt_order_retry<\/span><\/i><span style=\"font-weight: 400\"> hacer referencia al <\/span><i><span style=\"font-weight: 400\">entrada<\/span><\/i><span style=\"font-weight: 400\"> y <\/span><i><span style=\"font-weight: 400\">reintentar<\/span><\/i><span style=\"font-weight: 400\"> en la cubeta de pedidos<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">En <\/span><i><span style=\"font-weight: 400\">curlServicioCorreoHost<\/span><\/i><span style=\"font-weight: 400\"> especifica el alias de URL para el mock EmailService<\/span><\/li>\n<li style=\"font-weight: 400\">En <i>retryTimerIntervall<\/i> especifica el intervalo del temporizador en segundos.<\/li>\n<\/ul>\n<pre class=\"lang:default decode:true\">function OnUpdate(doc, meta) {\r\n\u00a0\u00a0\u00a0\u00a0if (meta.id === \"allow_retrys\") {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/ the timer is initialized by creating document with id = 'allow_retrys'\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0CreateRetryTimer({\"id\": meta.id, \"mode\": \"initial\"});\r\n\u00a0\u00a0\u00a0\u00a0} else if (doc.fireRetry) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/ process retry documents\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0SendConfirmationMail(doc, meta.id);\r\n\u00a0\u00a0\u00a0\u00a0}\r\n}\r\n\r\nfunction CreateRetryTimer(context) {\r\n\u00a0\u00a0\u00a0\u00a0if (debug_level &gt; 2) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0log('From CreateRetryTimer: creating timer', context.mode, context.id);\r\n\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\/\/ Create a timestamp 'retryTimerInterval' seconds (from the settings) from now\r\n\u00a0\u00a0\u00a0\u00a0var timerStartTime = new Date();\r\n\u00a0\u00a0\u00a0\u00a0\/\/ Get current time &amp; add 'retryTimerInterval' sec. to it.\r\n\u00a0\u00a0\u00a0\u00a0timerStartTime.setSeconds(timerStartTime.getSeconds() + retryTimerInterval);\r\n\u00a0\u00a0\u00a0\u00a0\/\/ Create a document to use as out for our context\r\n\u00a0\u00a0\u00a0\u00a0createTimer(RetryTimerCallback, timerStartTime, context.id, context);\r\n}\r\n\r\nfunction RetryTimerCallback(context) {\r\n\u00a0\u00a0\u00a0\u00a0if (debug_level &gt; 2) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0log('From RetryTimerCallback: timer fired', context);\r\n\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\/\/ rearm the timer ASAP, to ensure timer keeps running in the event\r\n\u00a0\u00a0\u00a0\u00a0\/\/ of later\u00a0 errors or script timeouts in later \"recurring work\".\r\n\u00a0\u00a0\u00a0\u00a0CreateRetryTimer({ \"id\": context.id, \"mode\": \"via_callback\" });\r\n\u00a0\u00a0\u00a0\u00a0\/\/ Update all retry documents in the 'retry' bucket. Exclude the 'allow_retys' document\r\n\u00a0\u00a0\u00a0\u00a0\/\/ and any documents that were created more than 15 seconds ago, in order to avoid retry 'to early'.\r\n\u00a0\u00a0\u00a0\u00a0N1QL(\"UPDATE orders._default.retry SET fireRetry = true WHERE meta().id != 'allow_retrys' AND ts &lt; DATE_ADD_MILLIS(NOW_MILLIS(), -15, 'second')\");\r\n}\r\n\r\nfunction SendConfirmationMail(retryDoc, docId) {\r\n\u00a0\u00a0try {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/ resolve order document by id\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0var doc = bkt_order_inbound[docId];\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/ build the request\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0var request = {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0path: 'sendConfirmation',\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0body: doc\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0};\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/\u00a0 perform the cURL request using the URL alias from the settings\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0var response = curl('POST', curlEmailServiceHost, request);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if (response.status != 200) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/ this did not work as expected\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if (debug_level &gt; 1) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0log(\"docId\", docId, \"cURL POST failed response.status:\",response.status);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/ increment attempt count in retry document\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0retryDoc.attempt = ++retryDoc.attempt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/ Set fireRetry = false, to avoid retry execution with this document change\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0retryDoc.fireRetry = false;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0retryDoc.ts = Date.now();\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/ update retry document\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0bkt_order_retry[docId] = retryDoc;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0} else {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0if (debug_level &gt; 5) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0log(\"cURL POST success, sent\",docId,\"response.body:\",response.body);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0doc.confirmationEmailSent = true;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0bkt_order_inbound[docId] = doc;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/ delete the retry document\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0delete bkt_order_retry[docId];\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\u00a0 } catch (e) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0log(\"ERROR cURL request had an exception:\",e)\r\n\u00a0\u00a0}\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<ul>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">El temporizador se inicia a\u00f1adiendo un documento con el id <\/span><b>allow_retrys<\/b><span style=\"font-weight: 400\"> a la <\/span><i><span style=\"font-weight: 400\">reintentar<\/span><\/i><span style=\"font-weight: 400\"> colecci\u00f3n<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">A continuaci\u00f3n, el temporizador se inicializa y la funci\u00f3n RetryTimerCallback asociada al temporizador<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Una vez ejecutado el temporizador se llama a la funci\u00f3n RetryTimerCallback<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">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.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Se utiliza una consulta N1QL para actualizar todos los <\/span><i><span style=\"font-weight: 400\">reintentar<\/span><\/i><span style=\"font-weight: 400\"> documentos en el <\/span><i><span style=\"font-weight: 400\">reintentar<\/span><\/i><span style=\"font-weight: 400\"> a\u00f1adiendo un <\/span><i><span style=\"font-weight: 400\">fireRetry<\/span><\/i><span style=\"font-weight: 400\"> al documento<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Cada cambio de documento da lugar a un evento de actualizaci\u00f3n del documento y se ejecuta el mecanismo de reintento<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">El documento de pedido se resuelve a partir del <\/span><i><span style=\"font-weight: 400\">entrada<\/span><\/i><span style=\"font-weight: 400\"> y el EmailService se llama a trav\u00e9s de cURL<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">En caso de fallo, el <\/span><i><span style=\"font-weight: 400\">reintentar<\/span><\/i><span style=\"font-weight: 400\"> y se actualiza el documento <\/span><i><span style=\"font-weight: 400\">intente<\/span><\/i><span style=\"font-weight: 400\"> contador aumentado<\/span><\/li>\n<\/ul>\n<p><b>Probar la aplicaci\u00f3n de ejemplo<\/b><\/p>\n<p><span style=\"font-weight: 400\">Ahora es el momento de probar finalmente la aplicaci\u00f3n de ejemplo:<\/span><\/p>\n<ol>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Aseg\u00farese de que el mock EmailService est\u00e1 en funcionamiento<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Inicie el <\/span><b><i>evt_send_confirmation_email <\/i><\/b><span style=\"font-weight: 400\">pero manteniendo el <\/span><b><i>evt_send_confirmation_email_retry <\/i><\/b><span style=\"font-weight: 400\">oyente se detuvo por ahora.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Cree un documento de pedido de muestra (v\u00e9ase el modelo de datos anterior) en la consola de Couchbase<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">En caso de respuesta positiva, el <\/span><span style=\"font-weight: 400\">confirmationEmailEnviado <\/span><span style=\"font-weight: 400\">se actualiza a true en el atributo <\/span><i><span style=\"font-weight: 400\">pedir<\/span><\/i><span style=\"font-weight: 400\"> documento.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">En caso de fallo, se crea un documento de reintento en la carpeta <\/span><i><span style=\"font-weight: 400\">reintentar<\/span><\/i><span style=\"font-weight: 400\"> recogida. Dado que el EmailService responder\u00e1 aleatoriamente con un error, repita el paso #3 hasta que se produzca un error.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Ahora que hemos capturado un error, vamos a iniciar el escuchador de eventos de reintento <\/span><b><i>evt_send_confirmation_email_retry<\/i><\/b><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Crea un documento con el id 'allow_retrys'. Esto inicializar\u00e1 el mecanismo de reintentos.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Al cabo de unos instantes, el oyente se activar\u00e1 y empezar\u00e1 a procesar los documentos de la base de datos. <\/span><i><span style=\"font-weight: 400\">reintentar<\/span><\/i><span style=\"font-weight: 400\"> colecci\u00f3n.<\/span><\/li>\n<li style=\"font-weight: 400\"><span style=\"font-weight: 400\">Por favor, observe que el atributo 'attempt' se incrementa con cada actualizaci\u00f3n fallida del Servicio de Correo Electr\u00f3nico. En caso de \u00e9xito, el documento de pedido se actualiza y el atributo <\/span><i><span style=\"font-weight: 400\">reintentar<\/span><\/i><span style=\"font-weight: 400\"> documento retirado del <\/span><i><span style=\"font-weight: 400\">reintentar<\/span><\/i><span style=\"font-weight: 400\"> colecci\u00f3n.<\/span><\/li>\n<\/ol>\n<p><span style=\"font-weight: 400\">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.<\/span><\/p>\n<p><b>Conclusi\u00f3n<\/b><\/p>\n<p><span style=\"font-weight: 400\">En este art\u00edculo 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\u00e1 temporalmente funcionando mal.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400\">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.<\/span><\/p>\n<p><span style=\"font-weight: 400\">Puedes encontrar m\u00e1s informaci\u00f3n sobre el funcionamiento interno de Couchbase Eventing aqu\u00ed: <\/span><a href=\"https:\/\/docs.couchbase.com\/server\/current\/eventing\/eventing-overview.html\"><span style=\"font-weight: 400\">https:\/\/docs.couchbase.com\/server\/current\/eventing\/eventing-overview.html<\/span><\/a><\/p>\n<p><span style=\"font-weight: 400\">Muchas gracias a Jon Strabala (Principal Product Manager, Couchbase) por sus conocimientos t\u00e9cnicos y su ayuda con este art\u00edculo.<\/span><\/p>","protected":false},"excerpt":{"rendered":"<p>The Couchbase Eventing Service allows you to promptly act on mutations (or changes) to your data. All actions in Eventing are accomplished by executing a lambda, a small piece of business logic written in JavaScript. Common use cases include data [&hellip;]<\/p>","protected":false},"author":77950,"featured_media":12473,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[2273],"tags":[],"ppma_author":[9323],"class_list":["post-12471","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-eventing"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.4 (Yoast SEO v26.4) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Couchbase Eventing Handling Errors and Retries w\/ Examples<\/title>\n<meta name=\"description\" content=\"This post will outline how errors during the event listener execution can be handled. By using a retry mechanism ensure the anticipated action is performed.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/es\/couchbase-eventing-handling-errors-and-retries\/\" \/>\n<meta property=\"og:locale\" content=\"es_MX\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Couchbase Eventing Handling Errors and Retries\" \/>\n<meta property=\"og:description\" content=\"This post will outline how errors during the event listener execution can be handled. By using a retry mechanism ensure the anticipated action is performed.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/es\/couchbase-eventing-handling-errors-and-retries\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2021-11-15T18:34:56+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-06-14T05:39:19+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/thisisengineering-raeng-64YrPKiguAE-unsplash-1024x683.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1024\" \/>\n\t<meta property=\"og:image:height\" content=\"683\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Marian Puhl, Senior Solutions Engineer\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Marian Puhl, Senior Solutions Engineer\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"9 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-eventing-handling-errors-and-retries\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-eventing-handling-errors-and-retries\/\"},\"author\":{\"name\":\"Marian Puhl, Senior Solutions Engineer\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/b2fc479528e2819b50082a425cf381e3\"},\"headline\":\"Couchbase Eventing Handling Errors and Retries\",\"datePublished\":\"2021-11-15T18:34:56+00:00\",\"dateModified\":\"2025-06-14T05:39:19+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-eventing-handling-errors-and-retries\/\"},\"wordCount\":1751,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-eventing-handling-errors-and-retries\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/thisisengineering-raeng-64YrPKiguAE-unsplash.jpg\",\"articleSection\":[\"Eventing\"],\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/couchbase-eventing-handling-errors-and-retries\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-eventing-handling-errors-and-retries\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/couchbase-eventing-handling-errors-and-retries\/\",\"name\":\"Couchbase Eventing Handling Errors and Retries w\/ Examples\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-eventing-handling-errors-and-retries\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-eventing-handling-errors-and-retries\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/thisisengineering-raeng-64YrPKiguAE-unsplash.jpg\",\"datePublished\":\"2021-11-15T18:34:56+00:00\",\"dateModified\":\"2025-06-14T05:39:19+00:00\",\"description\":\"This post will outline how errors during the event listener execution can be handled. By using a retry mechanism ensure the anticipated action is performed.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-eventing-handling-errors-and-retries\/#breadcrumb\"},\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/couchbase-eventing-handling-errors-and-retries\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-eventing-handling-errors-and-retries\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/thisisengineering-raeng-64YrPKiguAE-unsplash.jpg\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/thisisengineering-raeng-64YrPKiguAE-unsplash.jpg\",\"width\":7952,\"height\":5304,\"caption\":\"Creating JavaScript UDFs to traverse hierarchy in Couchbase SQL++\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-eventing-handling-errors-and-retries\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Couchbase Eventing Handling Errors and Retries\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"es\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"width\":218,\"height\":34,\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/b2fc479528e2819b50082a425cf381e3\",\"name\":\"Marian Puhl, Senior Solutions Engineer\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/1f65549252c18bb3651eaa3a78e46169\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/07\/marian-puhl-couchbase-engineering.jpeg\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/07\/marian-puhl-couchbase-engineering.jpeg\",\"caption\":\"Marian Puhl, Senior Solutions Engineer\"},\"description\":\"Marian Puhl is a Senior Solutions Engineer at Couchbase in the Nordic region.\",\"url\":\"https:\/\/www.couchbase.com\/blog\/es\/author\/marian-puhl\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Couchbase Eventing Handling Errors and Retries w\/ Examples","description":"Este post describir\u00e1 c\u00f3mo se pueden manejar los errores durante la ejecuci\u00f3n del listener de eventos. Mediante el uso de un mecanismo de reintento asegurar la acci\u00f3n prevista se lleva a cabo.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.couchbase.com\/blog\/es\/couchbase-eventing-handling-errors-and-retries\/","og_locale":"es_MX","og_type":"article","og_title":"Couchbase Eventing Handling Errors and Retries","og_description":"This post will outline how errors during the event listener execution can be handled. By using a retry mechanism ensure the anticipated action is performed.","og_url":"https:\/\/www.couchbase.com\/blog\/es\/couchbase-eventing-handling-errors-and-retries\/","og_site_name":"The Couchbase Blog","article_published_time":"2021-11-15T18:34:56+00:00","article_modified_time":"2025-06-14T05:39:19+00:00","og_image":[{"width":1024,"height":683,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/thisisengineering-raeng-64YrPKiguAE-unsplash-1024x683.jpg","type":"image\/jpeg"}],"author":"Marian Puhl, Senior Solutions Engineer","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Marian Puhl, Senior Solutions Engineer","Est. reading time":"9 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/couchbase-eventing-handling-errors-and-retries\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-eventing-handling-errors-and-retries\/"},"author":{"name":"Marian Puhl, Senior Solutions Engineer","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/b2fc479528e2819b50082a425cf381e3"},"headline":"Couchbase Eventing Handling Errors and Retries","datePublished":"2021-11-15T18:34:56+00:00","dateModified":"2025-06-14T05:39:19+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-eventing-handling-errors-and-retries\/"},"wordCount":1751,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-eventing-handling-errors-and-retries\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/thisisengineering-raeng-64YrPKiguAE-unsplash.jpg","articleSection":["Eventing"],"inLanguage":"es","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/couchbase-eventing-handling-errors-and-retries\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/couchbase-eventing-handling-errors-and-retries\/","url":"https:\/\/www.couchbase.com\/blog\/couchbase-eventing-handling-errors-and-retries\/","name":"Couchbase Eventing Handling Errors and Retries w\/ Examples","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-eventing-handling-errors-and-retries\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-eventing-handling-errors-and-retries\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/thisisengineering-raeng-64YrPKiguAE-unsplash.jpg","datePublished":"2021-11-15T18:34:56+00:00","dateModified":"2025-06-14T05:39:19+00:00","description":"Este post describir\u00e1 c\u00f3mo se pueden manejar los errores durante la ejecuci\u00f3n del listener de eventos. Mediante el uso de un mecanismo de reintento asegurar la acci\u00f3n prevista se lleva a cabo.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-eventing-handling-errors-and-retries\/#breadcrumb"},"inLanguage":"es","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/couchbase-eventing-handling-errors-and-retries\/"]}]},{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/couchbase-eventing-handling-errors-and-retries\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/thisisengineering-raeng-64YrPKiguAE-unsplash.jpg","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/11\/thisisengineering-raeng-64YrPKiguAE-unsplash.jpg","width":7952,"height":5304,"caption":"Creating JavaScript UDFs to traverse hierarchy in Couchbase SQL++"},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/couchbase-eventing-handling-errors-and-retries\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Couchbase Eventing Handling Errors and Retries"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"El blog de Couchbase","description":"Couchbase, la base de datos NoSQL","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"es"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"El blog de Couchbase","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","width":218,"height":34,"caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/b2fc479528e2819b50082a425cf381e3","name":"Marian Puhl, Ingeniera Superior de Soluciones","image":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/1f65549252c18bb3651eaa3a78e46169","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/07\/marian-puhl-couchbase-engineering.jpeg","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/07\/marian-puhl-couchbase-engineering.jpeg","caption":"Marian Puhl, Senior Solutions Engineer"},"description":"Marian Puhl es ingeniera de soluciones s\u00e9nior de Couchbase en la regi\u00f3n n\u00f3rdica.","url":"https:\/\/www.couchbase.com\/blog\/es\/author\/marian-puhl\/"}]}},"authors":[{"term_id":9323,"user_id":77950,"is_guest":0,"slug":"marian-puhl","display_name":"Marian Puhl, Senior Solutions Engineer","avatar_url":{"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/07\/marian-puhl-couchbase-engineering.jpeg","url2x":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2021\/07\/marian-puhl-couchbase-engineering.jpeg"},"author_category":"1","last_name":"Puhl, Senior Solutions Engineer","first_name":"Marian","job_title":"","user_url":"","description":"Marian Puhl es ingeniera de soluciones s\u00e9nior de Couchbase en la regi\u00f3n n\u00f3rdica."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts\/12471","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/users\/77950"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/comments?post=12471"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/posts\/12471\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/media\/12473"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/media?parent=12471"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/categories?post=12471"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/tags?post=12471"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/es\/wp-json\/wp\/v2\/ppma_author?post=12471"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}