Deduplicar avisos de multas en el receptor
La entrega al menos una vez es una promesa del productor; convertirla en un efecto único es trabajo del consumidor. Qué clave sirve, dónde se escribe la marca y cuánto hay que conservarla.
Un proveedor de avisos de multas promete entrega, no unicidad. Si la respuesta del receptor se pierde, si el proceso muere entre aplicar el efecto y confirmarlo, o si un operador reenvía una tanda retenida, el mismo aviso llega dos veces. PostgreSQL lo documenta para su replicación lógica: como la posición del slot se persiste recién en cada punto de control, tras una caída puede retroceder y el servidor reenvía cambios recientes al reiniciar. Y reparte la responsabilidad: los clientes deben evitar los efectos nocivos de procesar el mismo mensaje más de una vez.
El reparto vale para casi cualquier integración: el productor entrega al menos una vez y sólo el receptor puede convertir esa promesa en un efecto único. Deduplicar no es una optimización de rendimiento; evita que una garantía de entrega termine en un acta cargada dos veces o una segunda tarea de cobranza.
Duplicado de transporte y duplicado de negocio
Conviene separar dos problemas parecidos. Un duplicado de transporte es el mismo evento entregado más de una vez: mismo emisor, mismo identificador, mismo contenido. Un duplicado de negocio son dos eventos distintos sobre el mismo hecho, porque dos fuentes publican el acta o porque una jurisdicción la volvió a cargar.
Sólo el primero se resuelve con exactitud, comparando claves. El segundo es una decisión de correlación, con umbrales y revisión —una comparación campo por campo—, y no sale de la misma tabla. Mezclarlos lleva a descartar actas legítimas por parecidas, o a duplicar tareas por confiar en el transporte.
La clave la declara el productor
Un receptor no elige su clave de deduplicación: la hereda, y conviene leer con cuidado qué le entregan. CloudEvents exige que el productor haga única la combinación de origen e identificador para cada evento distinto, pero sobre los duplicados sólo abre permisos: un reenvío puede repetir ese par, y el consumidor puede asumir que dos eventos con el mismo par son duplicados. Un permiso no obliga a nadie: que un proveedor conserve el identificador entre reintentos hay que confirmarlo en su documentación. RFC 8417 reparte lo mismo en otro dominio, con un identificador de token único dentro de cada feed que el cliente puede usar para saber si ya lo recibió.
Tres claves tentadoras que fallan:
- el hash del cuerpo, que cambia con una reserialización o una firma nueva;
- el identificador del intento de entrega, que cambia en cada reintento;
- la patente más la fecha, que es correlación de negocio y arrastra un dato personal al índice.
La marca se escribe junto con el efecto
El error habitual es consultar si la clave existe y, si no aparece, procesar: entre la lectura y la escritura entra la segunda entrega, y dos procesos concurrentes cargan el acta dos veces.
La forma robusta es al revés: se inserta la clave con una restricción de unicidad y el conflicto decide; el que inserta procesa y el que choca confirma sin repetir nada. Esa inserción va en la misma transacción que el efecto. Si se confirma la marca primero y el proceso cae, el evento se pierde; si se aplica el efecto primero, un reintento lo duplica.
Cuando el efecto vive en otro sistema —una API de facturación, el tablero donde se carga el acta— no hay transacción común. Ahí conviene propagar la misma clave como clave de idempotencia, o registrar la intención y aplicarla con un proceso repetible sin daño.
La ventana tiene fecha de vencimiento
Ninguna tabla de deduplicación crece para siempre: se define una retención y las claves viejas se borran. Esa ventana debería superar el horizonte máximo de reintentos y reenvíos del proveedor, que suele estar escrito en su contrato de entrega.
Una clave que llega después del vencimiento no se distingue de una nueva: por eso la retención se elige por el peor caso del proveedor, no por costo de almacenamiento. Un aviso de acta muy atrasado es un caso de reconciliación contra el recurso canónico, no de aplicación a ciegas.
Qué responder y qué medir
Un duplicado no es, por sí solo, un error del productor. RFC 9110 llama idempotente al método cuyo efecto pretendido, ante varias solicitudes idénticas, es el mismo que el de una sola: eso es lo que el receptor fabrica cuando el transporte no se lo da. Y como un 2xx indica que la solicitud fue recibida, entendida y aceptada, esa es la respuesta que corresponde a un repetido. Devolver un error no describe lo que pasó y suele conseguir que el proveedor insista.
La tabla habilita además una cuenta que cierra: cada evento recibido termina aplicado o descartado por clave repetida, y esas dos series más las claves purgadas explican su tamaño. Si no cierra, algún camino aplica efectos sin dejar marca. Y conviene mirar la proporción, no el volumen: duplicados que suben mientras los aplicados no se mueven señalan confirmaciones lentas.
Antes de integrar, verificá tres cosas: que el productor documente qué campo identifica al evento y no lo cambie entre reintentos; que la clave y el efecto compartan transacción, o que la clave se propague al sistema que lo ejecuta; y que la retención supere la ventana de reenvío. La prueba es simple: reenviar la misma tanda dos veces, intercalada, y comprobar que el estado final y la cantidad de actas coinciden con los de una sola pasada.
Metodología
- Alcance
- Deduplicación de eventos entrantes en el sistema consumidor de una integración de infracciones. No cubre el diseño del productor, su política de reintentos ni la correlación entre actas informadas por fuentes distintas.
- Unidad de análisis
- Un evento entregado, identificado por la clave que declara el productor, y el efecto único que debe producir en el consumidor.
- Cobertura
- Se apoya en la identificación de eventos que definen CloudEvents y el token de eventos de seguridad, en la definición de idempotencia y el significado de los códigos 2xx de HTTP, y en la advertencia sobre repetición de mensajes de la replicación lógica de PostgreSQL. No describe el comportamiento de un proveedor en particular.
Limitaciones
- La deduplicación por clave resuelve reenvíos del mismo evento; no decide si dos eventos distintos describen el mismo hecho.
- La retención de claves acota el riesgo pero no lo elimina: un evento anterior a la ventana vuelve a parecer nuevo.
- Cuando el efecto vive en un sistema externo no hay transacción común, y la garantía depende de que ese sistema acepte una clave de idempotencia.
- CloudEvents permite que un reenvío repita el identificador, pero no lo exige: que un proveedor concreto lo conserve entre reintentos hay que verificarlo en su documentación.
Fuentes
- CloudEvents specification — Cloud Native Computing Foundation (consultada el )
- RFC 8417 — Security Event Token — RFC Editor (consultada el )
- RFC 9110 — HTTP Semantics — RFC Editor (consultada el )
- Conceptos de decodificación lógica y repetición de cambios — PostgreSQL Global Development Group (consultada el )
Preguntas frecuentes
¿Alcanza con guardar un hash del cuerpo para deduplicar un evento?
No es confiable. Una reserialización, una firma nueva o un campo de reintento cambian el hash del mismo evento, y dos eventos legítimos sin marca de tiempo propia pueden producir uno idéntico. Conviene usar el identificador que declara el productor.
¿Qué conviene responder cuando llega un evento repetido?
La misma confirmación que se devolvería al original. Según RFC 9110, un 2xx indica que la solicitud fue recibida, entendida y aceptada, que es justamente lo que pasó con el repetido. Contestar un error, además, suele hacer que el proveedor lo reintente todavía más.
¿Por qué no alcanza con consultar si la clave ya existe antes de procesar?
Porque dos entregas concurrentes pueden leer que no existe y aplicar el efecto dos veces. Es preferible insertar la clave con una restricción de unicidad y dejar que el conflicto decida cuál de las dos ejecuciones sigue adelante.
¿Se pueden borrar las claves viejas de la tabla de deduplicación?
Con una retención definida, sí. La ventana debería superar el horizonte máximo de reintentos y de reenvío manual del proveedor, porque una clave vencida vuelve a parecer nueva y su evento se aplicaría otra vez.
Notas relacionadas
Webhooks de nuevas multas: idempotencia, reintentos y trazabilidad
Un webhook confiable puede llegar más de una vez, demorarse o fallar después de ser procesado. El diseño debe deduplicar eventos, reintentar con límites y conservar evidencia de punta a punta.
Avisos de multas fuera de orden: cómo reconstruir el estado
Un aviso tardío no debería devolver a impaga un acta ya corregida. La solución es ordenar por revisión del recurso, procesar con idempotencia y reconciliar contra una fuente de verdad.
Datos sintéticos para probar una integración de multas
Mil filas parecidas ejercitan el mismo camino mil veces. Un conjunto de prueba se mide por las decisiones que obliga a tomar, y sus bordes se derivan del contrato en vez de inventarse.