Idempotency

Qué es

Una operación es idempotente cuando repetirla produce el mismo efecto observable que ejecutarla una sola vez. Para una transformación de estado f, la propiedad se expresa como f(f(s)) = f(s).

Asignar un valor fijo a una configuración puede ser idempotente. Incrementar un contador en cada ejecución no lo es. La propiedad depende del efecto observado y del alcance de la operación: no exige que cada respuesta, timestamp o registro de auditoría sea idéntico.

La igualdad se refiere a la misma intención y parámetros, y al estado o efecto elegido por el contrato. No exige una sola ejecución del código. No equivale a deduplicación: esta reconoce repeticiones y puede suprimirlas; la idempotencia describe qué efecto tiene repetir.

En HTTP, RFC 9110 define idempotencia respecto del efecto intencionado en el servidor. Admite logs auxiliares por solicitud y respuestas diferentes. Por eso idempotencia no exige respuestas byte a byte idénticas. RFC 9110, sección 9.2.2.

Qué problema resuelve

Después de un timeout, quien invoca una operación puede desconocer si el efecto ocurrió. retry permite recuperar progreso, pero también puede duplicar efectos. La idempotencia permite repetir una misma intención sin multiplicar su efecto dentro del alcance definido.

No garantiza entrega, éxito ni ejecución exactamente una vez. Tampoco elimina los problemas de concurrencia: una implementación debe impedir que dos intentos simultáneos apliquen el mismo efecto dos veces.

Cómo funciona

Algunas operaciones son naturalmente idempotentes; otras necesitan identificar una intención y recordar su resultado. API Idempotency desarrolla esta segunda opción. Reliable Execution conecta la propiedad con reintentos y resultados inciertos.

Propiedad de la operación

«Dejar activada esta configuración» converge al mismo estado al repetirla. «Activar alternando su valor» no. La propiedad debe cubrir todos los efectos de negocio relevantes. Un upsert que evita una segunda fila pero envía otro correo en cada intento es idempotente respecto de la fila, no respecto del envío.

La ecuación describe repeticiones de f; no prueba que otras operaciones puedan intercalarse sin consecuencias. Asignar valor = 100 es idempotente, pero una repetición tardía puede sobrescribir un cambio posterior a 200. Versiones o condiciones de actualización pueden evitar el cambio obsoleto: es un requisito adicional.

Contrato por intención

Una operación que naturalmente incrementa o crea puede incorporar identidad estable. «Registrar el crédito credito-17» puede producir un solo asiento aunque se solicite muchas veces. El sistema debe definir qué constituye una repetición, conservar su identidad y coordinar los intentos concurrentes.

Una clave enviada sin coordinación no ofrece protección. Si el efecto se confirma y la memoria de la intención no, otro intento puede repetirlo. Si ambos estados están en una transacción local, pueden confirmarse juntos; un efecto externo requiere colaboración de ese sistema o recuperación adicional. El dual-write-problem explica esa frontera.

Reutilizar una clave con parámetros incompatibles puede representar otra intención y debería resolverse explícitamente. El contrato también decide qué resultado devolver al repetir. AWS analiza identidad declarada por el cliente y solicitudes tardías; calcular un hash de parámetros no demuestra que dos peticiones tengan la misma intención. Making retries safe with idempotent APIs.

Ejemplo

Un cliente quiere reservar una unidad del producto A para el pedido 42. Recibe un timeout y vuelve a enviar la misma intención.

DiseñoSegundo intentoEfecto relevante
restar 1 al stock sin identidadVuelve a restarDos unidades descontadas.
asegurar reserva (pedido-42, A, 1) con unicidad y coordinaciónReconoce la reserva existenteUna reserva para esa intención.

El ejemplo presupone que reserva e identidad se confirman coherentemente. Un segundo pedido legítimo necesita otra identidad. Si un proveedor externo descuenta el stock real, la unicidad de la reserva local no garantiza un único descuento externo.

Cuándo usarlo

Es útil cuando pueden repetirse solicitudes, tareas o eventos: timeouts, recuperación de procesos, entrega at-least-once y replay de trabajo persistido. Separa la cantidad de intentos del efecto que necesita el negocio.

También simplifica converger a un estado deseado si se contemplan cambios concurrentes y versiones más recientes.

Cuándo NO usarlo

No fusionar acciones distintas porque sus parámetros coinciden. Dos compras iguales pueden ser dos intenciones, no un reintento. La identidad debe representar el dominio y el contrato del llamador.

No usarlo como sustituto de entrega, orden o atomicidad distribuida. Tampoco declarar un workflow completo idempotente después de comprobar una sola escritura interna.

Trade-offs y alternativas

La idempotencia natural puede ahorrar memoria de reintentos. Un contrato por clave necesita almacenamiento, retención, comparación de parámetros y recuperación de intentos en curso.

Al olvidar una identidad, una repetición tardía puede tratarse como nueva. Rechazar operaciones fuera del horizonte o conservar una identidad de negocio más duradera son alternativas con costos diferentes.

Idempotencia no implica conmutatividad: dos operaciones distintas pueden ser idempotentes y dar resultados diferentes según su orden. Tampoco es un cache de respuestas ni una garantía de disponibilidad.

Errores comunes: proteger solo un efecto interno, reservar una clave sin coordinar el efecto, cambiarla en cada intento o prometer protección por más tiempo que su retención.

Relaciones

  • deduplication distingue reconocimiento de repeticiones de equivalencia del efecto.
  • at-least-once explica por qué aparecen múltiples intentos.
  • exactly-once-semantics evalúa garantías sobre efectos confirmados.
  • dual-write-problem identifica ventanas cuando identidad y efecto se escriben por separado.
  • api-idempotency conserva la perspectiva sobre contratos de API.
  • idempotent-consumer conserva la perspectiva sobre procesamiento de mensajes, con idempotencia natural o deduplicación coordinada.