Módulo 2: Idempotencia: que repetir no duplique
1. Introducción: repetir sin hacer daño
Descripción
Al terminar esta lección vas a poder explicar, en una sola frase, qué es la idempotencia y por qué es la pieza central de un sistema de automatización confiable. Vas a tener el mapa completo de las ocho lecciones de este módulo —desde la definición con manzanas hasta el proyecto donde vuelves idempotente un paso real— y vas a saber exactamente qué problema de Cumbre resuelve cada una. También vas a reconocer, mirando el workflow order-triage que ya conociste en el módulo anterior, dónde está la herida por la que se cuela el segundo cobro.
Esto importa por una razón que ya viste en el módulo 1 y que conviene tener fresca: en n8n 2.0, un evento puede llegar más de una vez. El proveedor que dispara tu webhook reintenta si no recibe respuesta a tiempo. El cliente hace doble clic. El propio motor de n8n reintenta un paso que falló a la mitad. Nada de eso es un bug tuyo; es cómo funcionan los sistemas distribuidos. La entrega es "al menos una vez", no "exactamente una vez". Y si tu workflow trata cada llegada como si fuera nueva, cada repetición se convierte en un segundo cobro, un segundo correo o un registro duplicado. La idempotencia es la propiedad que hace que repetir sea seguro. Es, literalmente, lo que separa un workflow que funciona en la demo de un sistema que sobrevive en producción.
Conexión con el módulo: esta lección no te enseña todavía a construir nada. Es el mapa. Aquí retomas el problema que el módulo 1 dejó planteado —el webhook de Cumbre que se dispara dos veces y cobra dos veces—, defines en una frase la herramienta que lo resuelve, y recibes la ruta que vas a recorrer. La lección 2 define la idempotencia a fondo, con el botón del ascensor y el interruptor de la luz. Las lecciones 3, 4 y 5 te dan las tres piezas mecánicas: la clave que identifica el evento, el upsert que no duplica en la base de datos, y la cabecera que no duplica en una API. La lección 6 te advierte sobre la trampa más sutil de todas —"verificar y luego actuar"—, la 7 lleva todo esto al terreno de los agentes de IA, y la 8 lo junta en un proyecto que puedes defender en una entrevista.
El problema que dejamos abierto: el segundo cobro de Cumbre
Antes de definir nada, volvamos al lugar exacto donde el módulo 1 nos dejó, porque toda esta guía gira alrededor de una sola escena.
Cumbre es una distribuidora mayorista latinoamericana de café y té. Le vende a unas 400 cafeterías y tiendas pequeñas, y como es un equipo chico, automatiza todo lo que puede. Uno de sus workflows centrales se llama order-triage, y hace tres cosas, en este orden:
Webhook ──► AI Agent ──► HTTP Request
(recibe (clasifica el (escribe en el CRM
el pedido) pedido: prioridad, y dispara el cobro
canal, urgencia) y el correo)
El Webhook recibe el pedido cuando la tienda en línea lo dispara. El nodo AI Agent lo lee y lo clasifica —decide prioridad, detecta el canal, marca si es urgente—. Y el nodo HTTP Request toma esa decisión y ejecuta el efecto: crea el registro del pedido en el CRM y dispara el charge (el cobro al cliente) junto con el correo de confirmación.
En un mundo perfecto, cada pedido entra una vez, se clasifica una vez, se cobra una vez. Ese mundo no existe. Esto es lo que pasó un martes cualquiera:
La tienda en línea de Cumbre disparó el webhook con el pedido ORD-2041. La respuesta de n8n tardó un poco más de lo normal —el AI Agent se tomó tres segundos en clasificar—. La tienda, que espera una confirmación en dos segundos, asumió que el envío se había perdido y volvió a disparar el mismo pedido. Ahora order-triage corrió dos veces con el mismísimo ORD-2041. Dos clasificaciones. Dos escrituras al CRM. Y lo que de verdad duele: dos charge. Al cliente le llegó el cobro duplicado y dos correos de confirmación. Alguien en Cumbre tuvo que descubrir el cargo doble, pelearse con la pasarela de pago para revertirlo, y disculparse con el cliente.
Lo importante de esta escena es que nadie escribió un bug. El workflow está "bien" en el sentido de que cada nodo hace lo que dice hacer. El problema es que fue diseñado suponiendo que cada pedido llega exactamente una vez, y esa suposición es falsa. El módulo 1 te enseñó a ver esa falsedad —la entrega "al menos una vez", los modos de falla, la distinción entre lecturas (operaciones seguras de repetir, como consultar un dato) y efectos (operaciones peligrosas de repetir, como cobrar)—. Este módulo te enseña qué hacer al respecto.
Para tener presente el dato con el que trabajamos, este es el pedido ORD-2041 tal como le llega a order-triage por el webhook. Es el mismo item canónico de Cumbre que usa toda la guía, y lo vas a ver, con variaciones, en cada lección de este módulo:
{
"order_id": "ORD-2041",
"customer_id": "CUST-118",
"customer_name": "Luna Coffee",
"channel": "web",
"created_at": "2026-07-14T09:12:00.000Z",
"status": "pending",
"currency": "MXN",
"amount": 1780,
"line_items": [
{ "sku": "CF-ARA-500", "product_name": "Arabica Coffee 500g", "quantity": 12, "unit_price": 148.5 },
{ "sku": "TE-CHM-100", "product_name": "Chamomile Tea 100g", "quantity": 6, "unit_price": 62 }
]
}
Guarda en la memoria dos campos, porque van a ser los protagonistas del módulo: order_id, que identifica el pedido, y amount, el monto que hay que cobrar. Los identificadores están en inglés a propósito —order_id, no id_pedido— porque así es la convención de todo el ecosistema y del mercado tech real; la prosa va en español, el dato va en inglés.
De dónde vienen los dos disparos: las tres fuentes del duplicado
El módulo 1 ya las nombró; conviene recordarlas aquí porque la idempotencia existe precisamente para blindarte contra las tres, y ninguna de las tres es un error tuyo que puedas simplemente "arreglar".
El reintento del proveedor. El sistema que dispara tu webhook —la tienda en línea, una pasarela, otra plataforma— espera una respuesta en cierto plazo. Si tu workflow tarda más de la cuenta en responder, o si la respuesta se pierde en la red de vuelta, el proveedor asume que el envío falló y vuelve a enviar el mismo evento. Es un comportamiento correcto de su parte: prefiere entregar de más a entregar de menos. Esta es, por mucho, la fuente más común, y fue la que le pegó a ORD-2041.
El doble clic humano. Un cliente presiona "confirmar pedido", no ve respuesta inmediata, y vuelve a presionar. O un empleado, nervioso porque la pantalla se quedó pensando, dispara dos veces la misma acción. Dos eventos idénticos con segundos de diferencia. No lo controlas desde n8n.
El reintento del propio n8n. Cuando un nodo falla a la mitad —una caída de red justo cuando el HTTP Request ya mandó la petición pero antes de recibir la respuesta— n8n puede reintentar ese paso. Y aquí está lo traicionero: quizás la petición sí llegó a la pasarela y creó el cobro, pero la respuesta se perdió, así que n8n cree que falló y reintenta, creando un segundo cobro. El reintento, que es un mecanismo de confiabilidad, se convierte en una fuente de duplicados si lo que reintentas no es idempotente. El módulo 6 vuelve sobre esto en serio.
La conclusión práctica de las tres es la misma: no puedes cerrar todas las puertas por las que entra un duplicado. Puedes reducir algunas —responder rápido al webhook baja los reintentos del proveedor— pero siempre queda una rendija. Por eso la estrategia ganadora no es tapar puertas; es hacer que no importe cuántas veces entre el mismo evento. Eso es la idempotencia.
La idea en una frase: idempotencia
Aquí está la definición que vas a llevarte de todo el módulo, y que la lección 2 va a desarmar con calma:
Una operación es idempotente si ejecutarla muchas veces deja el mismo resultado que ejecutarla una sola vez.
Piénsalo con el botón del piso en un ascensor. Estás en la planta baja, quieres ir al piso 5, y aprietas el botón. Se enciende. Como el ascensor tarda, y porque somos humanos impacientes, lo aprietas cuatro veces más. ¿Llaman esos cinco toques a cinco ascensores? ¿Te llevan al piso 25? No. El botón registra "este señor va al piso 5" y ya. El primer toque cambió el estado; los otros cuatro no cambiaron nada. El resultado de apretarlo cinco veces es idéntico al de apretarlo una vez. Eso es idempotencia.
Ahora compáralo con un botón que no es idempotente: el de "agregar al carrito" en una tienda mal hecha. Le das clic cinco veces y terminas con cinco unidades del mismo producto. Cada clic sumó uno. El resultado de cinco clics es distinto del resultado de un clic. Ese botón no es idempotente, y por eso las tiendas buenas lo protegen —deshabilitan el botón después del primer clic, o cuentan cuántos ya agregaste—.
El charge de Cumbre es como el botón de "agregar al carrito": cada vez que corre, suma un cobro. Nuestro trabajo en este módulo es convertirlo en un botón de ascensor: que la segunda, la tercera y la quinta ejecución reconozcan "a este pedido ya lo cobré" y no hagan nada nuevo. El pedido se cobra una vez, sin importar cuántas veces llegue el webhook.
Fíjate en un matiz que vamos a repetir mucho, porque es la mitad del asunto: idempotente no significa "que no se ejecute dos veces". El webhook se va a disparar dos veces, y no siempre puedes evitarlo. Idempotente significa que no pasa nada malo cuando se ejecuta dos veces. No peleamos contra la repetición; la volvemos inofensiva.
Ejemplo trabajado: el mismo workflow, antes y después
Vamos a mirar order-triage en sus dos versiones, sin construir nada todavía. Solo para que veas hacia dónde vamos.
La versión frágil, la que cobró dos veces:
Webhook ──► AI Agent ──► HTTP Request (POST /charges)
crea un cobro nuevo, siempre
El nodo HTTP Request hace una petición POST a la pasarela de pago que dice, en esencia, "crea un cobro de 1780 pesos para el cliente CUST-118". Cada vez que corre, la pasarela crea un cobro nuevo, con un identificador nuevo. La pasarela no tiene forma de saber que este cobro y el anterior son "el mismo"; para ella son dos peticiones distintas que llegaron con un minuto de diferencia. Hace lo que le pediste: dos cobros.
La versión idempotente, hacia la que vamos:
Webhook ──► AI Agent ──► Code ──► HTTP Request (POST /charges)
(calcula el con la cabecera
idempotency_key) Idempotency-Key
Aparece un nodo Code nuevo cuyo único trabajo es calcular una clave de idempotencia estable para este pedido —un identificador que va a ser idéntico en la primera llegada y en la segunda, porque se deriva del contenido del pedido, no del momento en que llegó—. Y el HTTP Request ahora envía esa clave en una cabecera especial, Idempotency-Key, que las pasarelas de pago serias saben leer.
Qué esperar con la versión idempotente. La primera vez que llega ORD-2041, la pasarela ve una Idempotency-Key que nunca había visto, crea el cobro y guarda "esta clave ya la usé, el resultado fue este cobro". La segunda vez que llega —con la misma clave, porque se deriva del mismo pedido— la pasarela reconoce la clave, no crea un segundo cobro, y te devuelve el mismo resultado de la primera vez, como si acabara de hacerlo. Para tu workflow es transparente: recibe una respuesta exitosa las dos veces. Para el cliente, hay un solo cargo.
Puesto en una tabla, el contraste es toda la guía en cuatro celdas. Imagina que el webhook llega dos veces con ORD-2041:
| Después de la 1.ª llegada | Después de la 2.ª llegada | |
|---|---|---|
| Versión frágil | 1 cobro, 1 correo, 1 fila en el CRM | 2 cobros, 2 correos, 2 filas |
| Versión idempotente | 1 cobro, 1 correo, 1 fila en el CRM | 1 cobro, 1 correo, 1 fila (sin cambios) |
La fila de abajo es el destino de este módulo: la segunda llegada corre completa —no la bloqueamos— pero no deja ningún efecto nuevo. Corre "en vacío", como el segundo toque al botón del ascensor.
No te preocupes por los detalles todavía. Lo único que quiero que notes son tres cosas.
Primera: la solución no fue evitar que el webhook llegara dos veces. Llega dos veces igual. La solución fue hacer que la segunda llegada no cree un segundo efecto.
Segunda: apareció una pieza nueva, la idempotency_key, y todo depende de que esa clave sea la misma en las dos llegadas. Si la calculáramos mal —por ejemplo, usando la hora de llegada, que es distinta cada vez— la segunda llamada tendría una clave distinta, la pasarela la vería como nueva, y volveríamos a los dos cobros. Elegir bien esa clave es la lección 3, y es más sutil de lo que parece.
Tercera: esto solo funciona porque la pasarela de pago coopera —sabe leer la cabecera Idempotency-Key—. Cuando la API no coopera, o cuando el efecto es escribir en tu propia base de datos, la idempotencia hay que construirla de otra forma: con un upsert. Esa es la lección 4, y es la que más vas a usar.
Idempotencia no es "exactamente una vez"
Hay una confusión que conviene despejar temprano, porque si no, todo el módulo se siente como una solución a medias.
Cuando alguien descubre el problema del duplicado, su instinto es pedir una garantía de "exactamente una vez": que el sistema, de alguna forma mágica, asegure que cada evento se procese una sola vez, ni más ni menos. Suena a lo que uno quiere. El problema es que la entrega "exactamente una vez" en sistemas distribuidos es, en el sentido estricto, imposible de garantizar. Siempre puede caerse la red en el momento exacto en que no sabes si el efecto ocurrió o no. Ese es un resultado conocido y bien establecido en el diseño de sistemas, no una limitación de n8n.
Lo que sí se puede construir —y es lo que de verdad quieres— es la combinación de dos cosas: entrega "al menos una vez" (el evento puede llegar varias veces, y eso lo aceptamos) más procesamiento idempotente (procesarlo varias veces deja el mismo resultado que procesarlo una). El efecto combinado de las dos es, para todos los fines prácticos, "exactamente una vez": el cliente ve un solo cobro. Pero fíjate en cómo se logra. No se logra evitando la repetición —eso sería "exactamente una vez" de verdad, lo imposible—. Se logra aceptando la repetición y neutralizándola.
Piénsalo así: en vez de construir una puerta que nunca deja pasar a nadie dos veces —una puerta que no existe—, construyes una habitación donde da igual cuántas veces entre la misma persona, porque solo hay una silla con su nombre y siempre se sienta en la misma. Esa es toda la filosofía del módulo, y es más humilde y más robusta que la fantasía del "exactamente una vez".
Por qué esto es el corazón de la guía
Vale la pena decir con claridad por qué este módulo, el 2, es el centro de gravedad de toda la guía, y no uno más.
Todo lo que viene después se apoya en la idempotencia. La deduplicación del módulo 4 —el registro que lleva la cuenta de qué eventos ya procesaste— existe para poder aplicar idempotencia cuando la API no te da una cabecera. Los contratos del módulo 3 aseguran que la clave de idempotencia que un workflow le pasa a otro tenga la forma correcta. La coordinación del módulo 5 —el patrón outbox, el fan-out— depende de que cada efecto coordinado sea idempotente, porque si no, coordinar mal duplica en cadena. Y los reintentos del módulo 6 solo son seguros si lo que reintentas es idempotente; reintentar un efecto que no lo es es, precisamente, cómo se fabrican los duplicados.
Dicho al revés: si sales de este módulo dominando la idempotencia, el resto de la guía es aprender dónde guardar el estado y cómo coordinar; pero la propiedad fundamental ya la tienes. Si sales sin dominarla, todo lo demás se construye sobre arena.
Por eso vamos a ir despacio y con muchas manzanas. No hay prisa. Un concepto a la vez.
El mapa de este módulo
Estas son las ocho lecciones y qué resuelve cada una. Te conviene volver a esta tabla al terminar cada lección para no perder el hilo.
| Lección | Qué resuelve | La pieza de Cumbre que toca |
|---|---|---|
| 2 | Qué es exactamente la idempotencia, y qué operaciones ya lo son por naturaleza y cuáles no | Por qué el charge no es idempotente y una consulta al CRM sí |
| 3 | Cómo elegir la clave que identifica "el mismo evento" entre reintentos: natural vs sintética | Elegir la idempotency_key de ORD-2041 |
| 4 | El upsert: insertar-o-actualizar por clave en vez de insertar a ciegas | Convertir la escritura al CRM en un upsert por order_id |
| 5 | La cabecera Idempotency-Key para APIs que la soportan, y el patrón para las que no | Hacer idempotente el charge en la pasarela |
| 6 | La trampa de verificar-y-luego-actuar: por qué "busco si existe y si no lo creo" falla | El error sutil que sobrevive a la prueba y explota en producción |
| 7 | Idempotencia para las acciones de un AI Agent: cuando el agente llama una herramienta con efecto | Hacer que el AI Agent de Cumbre no cobre dos veces al reintentar |
| 8 | Proyecto: tomar un paso que crea registros y volverlo idempotente, y probarlo | El order-triage completo, re-ejecutado sin duplicar |
Fíjate en el orden, porque no es arbitrario. Primero el qué (lección 2): la definición limpia, para que reconozcas una operación idempotente cuando la veas. Después las tres herramientas en orden de dependencia: la clave (3) es la materia prima de todo lo demás; el upsert (4) es el mecanismo para tus propios datos; la cabecera (5) es el mecanismo para APIs de terceros. Luego la advertencia (6), porque la solución ingenua —dos nodos, "revisa y crea"— es tan tentadora y tan rota que merece su propia lección. Después la aplicación al caso de moda (7), los agentes. Y al final el proyecto (8), que no introduce nada nuevo: junta las seis piezas anteriores en un entregable.
Si te sirve una imagen: las lecciones 3, 4 y 5 son las tres herramientas de una misma caja. La 3 es "cómo le pones nombre único a cada evento". La 4 es "cómo lo guardas sin duplicar en tu casa". La 5 es "cómo se lo pides sin duplicar a la casa de otro". La 6 es la etiqueta de advertencia pegada a la caja.
Una nota sobre lo que NO vas a construir aquí
Para que sepas dónde estás parado, dos límites honestos.
Este módulo no construye el almacén de deduplicación. Vas a hacer idempotente una operación con las herramientas de este módulo. El registro persistente que recuerda, entre ejecuciones distintas y a lo largo de semanas, qué eventos ya procesaste —el ledger de deduplicación— es el módulo 4. Aquí vas a usar la idempotencia que te dan la propia API (con su cabecera) y la propia base de datos (con su upsert); el módulo 4 te enseña a construirla tú mismo cuando ninguna de las dos te la regala.
Este módulo no opera en producción. Reintentos seguros, alertas cuando algo de verdad falla, y reproducir un bug de duplicado con el motor de replay de n8n 2.0 son el módulo 6. Aquí diseñas la correctitud; allá la vigilas. Es la frontera que la guía completa declara al final.
Lo digo porque es fácil, al aprender idempotencia, querer resolver todo de una vez. No hace falta. La operación segura primero; el estado y la operación, después.
Si te sirve una metáfora para ubicar los seis módulos: la idempotencia de este módulo es aprender a que un solo interruptor no electrocute a nadie por más veces que lo aprietes. El módulo 3 (contratos) es acordar qué voltaje entra y sale de cada interruptor. El módulo 4 (modelo de datos) es el tablero central que recuerda qué interruptores ya se accionaron. El módulo 5 (dependencias) es coordinar que varios interruptores se accionen en el orden correcto sin pisarse. Y el módulo 6 (reintentos y alertas) es el sistema que avisa cuando un interruptor de verdad se quemó. Todo el edificio se apoya en el primer ladrillo —un interruptor seguro— y ese ladrillo es lo que pones en su lugar en estas ocho lecciones.
Errores comunes
Creer que idempotencia significa "que no corra dos veces" (conceptual). Qué pasa: alguien entiende que el problema es la doble ejecución y gasta toda su energía en evitarla —pone un candado, deshabilita reintentos, ruega que el proveedor no reintente—. Por qué pasa: es la lectura intuitiva, y no es del todo falsa; reducir las ejecuciones duplicadas ayuda. Pero es una defensa que siempre tiene grietas: no controlas los reintentos del proveedor, ni el doble clic del cliente, ni una caída de red que hace que n8n reintente. Cómo detectarlo: si tu plan para el segundo cobro es "voy a asegurarme de que el webhook no llegue dos veces", estás peleando la batalla equivocada. Cómo corregirlo: cambia el objetivo. No evites la repetición; hazla inofensiva. Un sistema idempotente asume que todo va a llegar dos veces y se diseña para que no importe. Esa es la mentalidad de todo el módulo.
Confundir "no dio error" con "no duplicó" (conceptual). Qué pasa: se prueba el workflow, corre dos veces, ninguna de las dos arroja un error rojo, y se concluye que está bien. Por qué pasa: un efecto duplicado casi nunca falla ruidosamente. La segunda llamada a la pasarela es una petición perfectamente válida que devuelve 200 OK; el segundo INSERT al CRM se ejecuta sin problema y crea una fila nueva. El daño no es un error, es un éxito de más. Cómo detectarlo: no mires si hubo error; cuenta los efectos. Después de correr dos veces, ¿cuántos cobros hay en la pasarela? ¿Cuántas filas en el CRM? Cómo corregirlo: adopta desde ya el criterio de prueba de este módulo, que la lección 8 formaliza: la prueba de idempotencia no es "corrió sin error", es "corrí dos veces y hay exactamente un efecto".
Querer resolverlo todo en el módulo equivocado (conceptual). Qué pasa: al aprender idempotencia, alguien intenta construir de una vez el registro persistente de eventos procesados, la alerta, el reintento y la coordinación. Se abruma y no termina ninguna. Por qué pasa: los temas están relacionados y es natural verlos juntos. Cómo detectarlo: si para hacer idempotente un cobro sientes que primero necesitas una tabla de auditoría, un sistema de alertas y una cola de mensajes muertos, estás mezclando módulos. Cómo corregirlo: quédate con el alcance de este módulo —una operación, una clave, un upsert o una cabecera— y confía en que el estado (módulo 4), la coordinación (módulo 5) y la operación (módulo 6) llegan después, con sus propias herramientas.
Ejercicios
Ejercicio 1 — Encuentra la herida. Vuelve al diagrama de order-triage frágil (Webhook → AI Agent → HTTP Request). En una o dos frases, di cuál de los tres nodos es el que causa el daño cuando el workflow corre dos veces, y por qué los otros dos, aunque también corren dos veces, no dejan un problema permanente.
Ver solución
El nodo que causa el daño permanente es el HTTP Request, porque es el que ejecuta un efecto: crea un cobro en la pasarela y dispara un correo. Cada vez que corre, produce un cambio nuevo en el mundo de afuera —un cargo más, un correo más— y esos cambios no se deshacen solos.
El Webhook corre dos veces, sí, pero recibir un pedido dos veces no deja rastro dañino por sí mismo; es solo dato que entra. El AI Agent también clasifica dos veces, y clasificar es esencialmente una lectura razonada: produce una decisión (prioridad, urgencia) pero no cambia nada afuera. Clasificar el mismo pedido dos veces desperdicia un poco de cómputo, pero no cobra de más ni manda un correo de más.
Por qué funciona: estás aplicando la distinción del módulo 1 —lecturas vs efectos— a un caso concreto. El peligro de la repetición vive en los efectos, no en las lecturas. Todo este módulo se concentra en volver seguros los efectos, y por eso el HTTP Request es el protagonista.
Ejercicio 2 — Idempotente o no. Para cada una de estas operaciones cotidianas, decide si es idempotente (repetirla deja el mismo resultado que hacerla una vez) o no, y explica en una frase por qué:
(a) Apagar la luz de una habitación con un interruptor. (b) Servirte una cucharada de azúcar en el café. (c) Poner el volumen del televisor en 15 con el control (el que tiene teclado numérico, no las flechas de subir/bajar). (d) Subir el volumen del televisor con la flecha de "volumen +".
Ver solución
(a) Idempotente. Apagar una luz que ya está apagada la deja apagada. El estado final es "apagada", lo hagas una vez o diez. Es del tipo "poner el estado en un valor fijo".
(b) No idempotente. Cada cucharada suma azúcar. Una cucharada endulza; cinco cucharadas arruinan el café. El resultado depende de cuántas veces lo hagas. Es del tipo "incrementar".
(c) Idempotente. Escribir "15" en el teclado pone el volumen en 15, sin importar cuántas veces lo escribas. El estado final es "volumen = 15". Es, otra vez, "poner el estado en un valor fijo" —el mismo patrón que el botón del piso del ascensor—.
(d) No idempotente. Cada toque de "volumen +" sube uno. Cinco toques suben cinco. Es "incrementar", igual que la cucharada de azúcar.
Por qué funciona: la línea que separa (a) y (c) de (b) y (d) es exactamente la línea que separa lo idempotente de lo que no lo es. Fijar un estado a un valor absoluto ("que sea 15", "que quede apagada") es idempotente. Modificar el estado en relación con lo que ya había ("suma uno", "agrega una cucharada") no lo es. En la lección 2 vas a ver esta misma distinción en operaciones de base de datos y de API, y es la herramienta mental que más vas a usar.
Ejercicio 3 — Reconstruye el mapa. Sin volver a mirar la tabla de la sección "El mapa de este módulo", escribe de memoria qué resuelve cada una de las siete lecciones que siguen (2 a 8), en una frase cada una. Después compara y marca las que se te escaparon.
Ver solución
(2) Qué es la idempotencia y qué operaciones ya lo son por naturaleza. (3) Cómo elegir la clave que identifica el mismo evento entre reintentos, natural o sintética. (4) El upsert: insertar-o-actualizar por clave en tu base de datos en vez de insertar a ciegas. (5) La cabecera Idempotency-Key para APIs que la soportan, y qué hacer con las que no. (6) La trampa de "verificar y luego actuar" y por qué no basta. (7) Idempotencia para las acciones con efecto de un AI Agent. (8) El proyecto: volver idempotente un paso que crea registros y probarlo re-ejecutando.
Por qué funciona: si reconstruiste al menos cinco de las siete, ya internalizaste la progresión del módulo, que va de la definición (2) a las tres herramientas (3, 4, 5) a la advertencia (6) a la aplicación (7) al proyecto (8). Las que más se escapan suelen ser la 3 y la 6, que son las más conceptuales hasta que las ves en código.
Resumen y siguiente paso
En esta lección retomaste el problema que el módulo 1 dejó abierto: el workflow order-triage de Cumbre, que cuando el webhook se dispara dos veces con el mismo ORD-2041 termina creando dos cobros y dos correos, sin que nadie haya escrito un bug —el workflow simplemente supuso que cada pedido llega una sola vez, y esa suposición es falsa—. Conociste la definición que gobierna todo el módulo: una operación es idempotente si ejecutarla muchas veces deja el mismo resultado que ejecutarla una. La viste con el botón del piso del ascensor —apretarlo cinco veces no llama cinco ascensores— frente al botón de "agregar al carrito", que suma uno por clic. Y viste, sin construirlo todavía, cómo se ve order-triage en su versión idempotente: una clave estable calculada en un nodo Code y una cabecera Idempotency-Key que hace que la segunda llegada no cobre de nuevo.
Lo más importante que te llevas es un cambio de objetivo: no vamos a evitar que las cosas ocurran dos veces —no siempre podemos—; vamos a hacer que ocurrir dos veces no haga daño.
Antes de avanzar a la lección 2 deberías poder: definir idempotencia en una frase; explicar por qué el charge de Cumbre no lo es y una consulta al CRM sí; y distinguir "fijar un estado a un valor" (idempotente) de "modificar el estado en relación con lo que había" (no idempotente).
La lección 2 toma esa definición y la desarma con calma. Vas a ver por qué ciertas operaciones ya son idempotentes por naturaleza y ni siquiera tienes que hacer nada, cuáles nunca lo son y hay que protegerlas, y dónde encajan en esto los métodos de HTTP —GET, PUT, DELETE, POST— que ya usas todos los días sin saber que la mitad de ellos ya te estaban dando idempotencia gratis.
Recursos
- Idempotency — MDN Web Docs Glossary — la definición formal de idempotencia aplicada a métodos HTTP, corta y precisa. Es la referencia canónica del término y la base de la lección 2.
- Webhook node — n8n Docs — el nodo que dispara
order-triage; conviene revisar cómo responde y qué pasa cuando el emisor reintenta. - Error handling — n8n Docs — el marco general de qué hace n8n cuando un paso falla y reintenta, que es una de las tres fuentes de duplicados de este módulo.
- Idempotency — Stripe API reference — cómo una pasarela de pago real implementa la idempotencia con una cabecera; la vamos a estudiar en detalle en la lección 5. Verifica siempre el nombre exacto de la cabecera y las condiciones vigentes aquí.