Fallos en red, incertidumbre e idempotencia
¿Alguna vez has pulsado «Pagar» o «Reservar», la conexión se ha quedado pensando sin responder y has dudado de si volver a pulsar te cobrará dos veces? Esa duda no es un capricho del usuario: es uno de los problemas lógicos más importantes de los sistemas comunicados.
Objetivos y conocimientos previos
Integrando todo el Curso III, aprenderás por qué en cualquier comunicación por red existen tres resultados posibles (éxito, fallo conocido e incertidumbre), qué peligro introducen los reintentos automáticos o manuales, y cómo el concepto de idempotencia permite repetir una solicitud con total seguridad.
Los tres estados reales de una petición por red
Cuando un componente llama a otro dentro de la misma memoria, sabe inmediatamente si la operación terminó. Pero cuando la llamada viaja por una red (del teléfono al servidor, o de tu servidor a una pasarela de pagos), el mensaje de ida o el mensaje de vuelta pueden perderse o demorarse.
Desde el punto de vista de quien envía la solicitud, existen tres situaciones posibles:
| Lo que recibe el cliente | Qué ocurrió realmente en el servidor | ¿Hay certidumbre? |
|---|---|---|
| 1. Respuesta de Éxito | El servidor recibió la petición, aplicó el cambio y la confirmación llegó de vuelta. | Sí: sabemos que se ejecutó. |
| 2. Respuesta de Rechazo (antes de ejecutar) | El servidor (o la red antes de llegar a él) rechazó la solicitud sin aplicar cambios. | Sí: sabemos que no se aplicó. |
| 3. Tiempo agotado (Timeout) o corte de conexión | No lo sabemos: puede que la petición nunca llegara al servidor, o puede que el servidor sí ejecutara el cobro/reserva y la conexión se cortara un milisegundo después, cuando el mensaje de «Éxito» venía de regreso. | No: estado de incertidumbre. |
- 1. Cliente envía: «Cobrar 50 € de la factura F-104»
- 2. Servidor procesa y guarda el cobro de 50 €
- 3. ¿Llega la respuesta de confirmación al cliente?Sí llega
- Cliente y servidor coinciden: factura pagada
Se corta la red al volver- El servidor ya cobró, pero el cliente ve un error de conexión
Si ante ese corte de conexión el usuario (o el propio programa automáticamente) vuelve a enviar «Cobrar 50 €» y el servidor lo trata como una orden nueva e independiente, cobrará 100 €.
Qué es la idempotencia
En lógica y matemáticas, una operación es idempotente cuando aplicarla varias veces seguidas produce exactamente el mismo estado en el sistema que aplicarla una sola vez, y permite devolver una respuesta coherente en cada intento.
Compara estas dos formas de expresar una operación:
| Operación NO idempotente (Peligrosa al reintentar) | Operación Idempotente (Segura al reintentar) |
|---|---|
| «Súmale 1 al contador de plazas ocupadas» (Si se envía dos veces por un reintento de red, suma 2 plazas para una sola persona). | «Asegura que la reserva R-405 de Ana para la actividad A-10 esté en estado CANCELADA» (La primera vez la pasa de ACTIVA a CANCELADA; la segunda vez ve que ya está CANCELADA, no altera el aforo y confirma el estado). |
| «Crea un cobro nuevo de 50 € a este cliente» (Cada reintento crea un cobro adicional). | «Ejecuta el intento de pago con clave única de operación OP-2026-9981 para la factura F-104». |
Cómo lograr idempotencia en creaciones y pagos (Clave de idempotencia)
Cancelar una reserva concreta por su identificador (R-405) o fijar un estado final es naturalmente idempotente si revisamos el estado previo. Pero ¿qué ocurre cuando estamos creando algo nuevo (una reserva, un pago, una factura) que todavía no tiene identificador en el servidor?
La solución clásica en sistemas consiste en asignar a la intención del usuario una clave de idempotencia (o restricción de unicidad del dominio) antes de enviar la solicitud:
- Cuando el usuario va a pagar la factura
F-104(o cuando solicita reservar en la actividadA-10), la solicitud incluye un identificador único de esa intención: por ejemplo, la pareja(id_persona, id_actividad)para reservas donde solo se admite una por persona, o un código único de intento de pagoid_intento_pagogenerado al abrir el formulario de pago. - El servidor registra esa clave dentro de la misma transacción en que guarda el resultado.
- Si la respuesta se pierde y el cliente reintenta enviando la misma clave
id_intento_pago:- El servidor detecta que esa clave ya fue procesada.
- No vuelve a ejecutar el cobro.
- Devuelve directamente el resultado que ya había guardado para esa clave.
Así desaparece el dilema: el cliente puede reintentar sin miedo cuando cae la red, sabiendo que el servidor reconocerá que se trata de la misma operación.
Límites en los reintentos
Que una operación sea idempotente hace seguro reintentarla, pero reintentar sin pausa ni límite cuando un servidor está sobrecargado o caído empeora el fallo. Por eso, todo mecanismo de reintento debe cumplir tres reglas (como vimos en Algoritmos):
- Solo reintentar operaciones idempotentes (o tras consultar primero el estado real).
- No reintentar errores de regla de negocio: si el servidor respondió explícitamente «Aforo completo» o «Saldo insuficiente», reintentar diez veces en un segundo es inútil. Solo tienen sentido los reintentos ante fallos transitorios de comunicación o disponibilidad.
- Establecer un número máximo de intentos y una espera creciente, informando claramente al usuario si al agotarse el resultado sigue sin confirmarse.
Practica
Un agente ha creado un sistema de facturación donde el administrador pulsa el botón «Emitir facturas del mes a todos los socios». Al probarlo con una conexión móvil inestable, el administrador pulsa el botón, espera 10 segundos sin respuesta y vuelve a pulsarlo. Al día siguiente descubre que todos los socios tienen dos facturas idénticas emitidas para el mismo mes de octubre de 2026.
- Explica paso a paso por qué ocurrió la duplicación usando el concepto de respuesta perdida / incertidumbre.
- ¿Por qué deshabilitar el botón en la pantalla tras el primer clic ayuda contra un doble clic rápido del ratón, pero no basta si el usuario recarga la página tras un corte de red y vuelve a pulsar?
- Define la regla de unicidad e idempotencia que exigirías en el modelo de datos y en el contrato del servidor para que sea imposible emitir dos facturas de cuota mensual al mismo socio para el mismo período (
año-mes), aunque la orden se envíe tres veces.
Criterio de comprensión: debes exigir en el servidor y en la base de datos una restricción única por (id_socio, periodo_mensual) (o clave de idempotencia del lote mensual) de modo que un segundo envío para el mismo socio y mes no duplique el registro sino que reconozca la factura ya emitida.
Profundiza con IA
Aquí tienes mi solución para hacer idempotente la emisión mensual de facturas: [tu respuesta]. Evalúa si mi regla cubre tanto el doble clic como el reintento tras recargar la página. Después, pregúntame qué ajuste necesitaría mi modelo si un socio tuviera una factura de octubre que fue
ANULADApor un error y ahora sí necesitamos emitirle una nueva factura válida para ese mismo mes de octubre.
Cierre del Curso III y próximo paso
Ya comprendes cómo se modela un sistema de extremo a extremo: datos con estado e invariantes, componentes desacoplados, fronteras de confianza protegidas, contratos explícitos y comunicación resistente a fallos mediante idempotencia.
En el Curso IV — Abstracción, Ejecución y Entornos veremos dónde cobra vida todo esto: cómo las capas de hardware, sistema operativo, lenguajes formales y entornos de ejecución (cliente y servidor) materializan los modelos lógicos y qué límites físicos debes tener en cuenta.