Exactly-once es una mentira: diseñar integraciones para duplicados

Tres copias de la misma ficha de mensaje convergiendo en una única ficha procesada

En algún lugar de todo contrato de integración hay una frase como «cada pedido se transmitirá exactamente una vez». Nunca ha sido cierta, ni una sola vez. La red se particionó a mitad de la solicitud y el emisor reintentó; la cola reentregó el mensaje tras el fallo de un consumidor; un operario de almacén pulsó el botón de exportar dos veces. Los duplicados no son un modo de fallo - son el clima.

Claves de idempotencia, elegidas con cuidado

La solución es antigua y poco vistosa: cada mensaje lleva una clave, y el procesamiento no hace nada cuando esa clave ya se ha visto. Las decisiones interesantes están todas en la elección de la clave.

  • Las claves naturales superan a las generadas. Una sincronización de pedidos con clave order_id + status sobrevive a que el emisor regenere su outbox; un UUID aleatorio acuñado en el momento del envío no.
  • Ámbito de la clave al efecto, no al mensaje. Si un mensaje crea una factura y reserva stock, esos son dos efectos con dos claves - de lo contrario, un fallo parcial te deja sin poder reintentar con seguridad ninguno de los dos.
  • Caduca las claves de forma deliberada. Un almacén de deduplicación que crece indefinidamente es una bomba de relojería; uno que caduca demasiado pronto reintroduce duplicados. Por defecto usamos 3 veces el horizonte máximo de reintento del emisor.

La prueba que importa

Toda integración que entregamos pasa lo que internamente llamamos la prueba del doble toque: reproducir todo el registro de mensajes de ayer contra el sistema de hoy, dos veces, y comparar el estado resultante. Si algo cambió en la segunda pasada, el pipeline no está terminado.

Es una prueba brutal y falla constantemente durante el desarrollo - por marcas de tiempo, por campos de auditoría «creado por», por contadores de secuencia. Cada fallo es un lugar donde una reentrega a las 3 de la madrugada habría corrompido datos silenciosamente. Sale mucho más barato detectarlo en desarrollo que en producción.