Reintentos de webhooks y mensajes duplicados
Cómo distinguir si los mensajes duplicados vienen de reintentos de webhooks o de eventos separados, y cómo rastrear la causa real.

¿Por qué los reintentos de webhooks están causando mensajes duplicados?
Los reintentos de webhooks son útiles… hasta que dejan de serlo. Un solo timeout perdido puede convertirse en dos mensajes, luego en tres, y de repente la misma actualización de pedido, el restablecimiento de contraseña o el aviso de envío aparece más de una vez. Ahí es cuando la pregunta "por qué los reintentos de webhooks causan mensajes duplicados" deja de ser teórica y empieza a costar tiempo.
El primer error es asumir que todo mensaje repetido significa que el remitente está fallando. A veces el remitente reintentó exactamente como estaba diseñado. A veces tu receptor respondió demasiado lento. A veces una cola, un worker o una repetición de registros creó la copia extra después de que el webhook ya había llegado una vez. Son problemas distintos, y necesitan soluciones distintas. Entender cómo evitar mensajes duplicados por webhooks empieza por distinguir estas causas.
¿Estos duplicados vienen de reintentos o de eventos de webhook separados?
Empieza por la prueba más simple: compara los payloads. Si dos entregas comparten el mismo ID de evento, el mismo ID de entrega o los mismos metadatos de firma, probablemente estás viendo un solo evento entregado más de una vez. Si los datos de negocio son parecidos pero los IDs difieren, es posible que el remitente haya creado dos eventos reales, como dos acciones de checkout o dos cambios de estado. Esa es la base para detectar duplicados en webhooks y reintentos con confianza.
No confíes solo en la marca de tiempo. Dos entregas que llegan con 12 segundos de diferencia aún pueden ser el mismo evento, mientras que dos mensajes que llegan en el mismo segundo pueden seguir siendo eventos separados. Un bucle de reintentos y un duplicado real pueden parecer casi idénticos en una bandeja de entrada, por eso los IDs importan más que el ojo humano.
Hay una pista práctica aquí. Si tu equipo de soporte ve alertas de correo duplicadas, pero los logs del webhook muestran un evento original y un reintento con los mismos metadatos de entrega, el problema probablemente esté en el transporte. Si los logs muestran dos payloads distintos con IDs de evento diferentes, el duplicado viene de más arriba. Esa distinción ahorra horas.
¿Qué comportamiento de reintento está usando realmente el remitente?
Distintos proveedores gestionan los reintentos de distintas maneras. Algunos reintentan automáticamente tras un timeout. Algunos permiten que un operador pulse reenviar. Algunos reentregan después de un código de fallo temporal. Unos pocos hacen las tres cosas. Si no sabes cuál está activo, tu búsqueda de mensajes duplicados dará vueltas en círculo.
Un reenvío manual suele dejar un rastro humano: una acción en el panel, una nota de ticket o un caso de soporte. Los reintentos automáticos suelen seguir un patrón, a menudo con intervalos crecientes entre intentos. Las políticas de reentrega del lado del proveedor pueden ser más silenciosas, porque el remitente puede tratar un fallo de red, un problema de DNS o una respuesta 5xx como motivo para intentarlo otra vez sin que nadie toque el panel.
Pide por escrito la política de reintentos del remitente. Un proveedor puede reintentar durante 24 horas; otro puede detenerse tras 3 intentos; otro puede considerar cualquier respuesta que no sea 2xx como un fallo. Eso importa porque un mensaje que "se duplica" después de 15 minutos puede ser simplemente el intento 4 de la misma entrega.
¿Qué hace que una entrega de webhook parezca varios mensajes aguas abajo?
El webhook puede estar bien. La duplicación puede ocurrir después. Una sola entrega puede pasar a una cola, luego a dos consumidores, luego a una tarea reintentable y, finalmente, a dos notificaciones salientes. El webhook original era un solo mensaje; tu sistema lo hizo parecer varios.
Eso es especialmente común cuando el controlador escribe en una cola antes de confirmar un registro en la base de datos, o cuando dos workers consumen la misma tarea después de un timeout de visibilidad. Un webhook se convierte en varias acciones posteriores porque el estado interno no estaba bien bloqueado. El resultado parece que el remitente reintentó, pero la duplicación real ocurrió dentro de tu propia pila.
Fíjate en dónde ocurre el primer efecto secundario. ¿Se envió el correo antes del insert en la base de datos? ¿Se marcó la factura como pagada después de iniciar la tarea de notificación? ¿Se volvió a poner en cola la tarea porque el worker se cayó en el momento equivocado? Esos detalles importan más que el error principal.
¿Cómo pueden los IDs del payload y los metadatos de entrega revelar la causa real?
Los IDs del payload son tu mejor evidencia. El ID de evento, el ID de entrega, el contador de intentos, la firma de la solicitud y la marca de tiempo del proveedor pueden mostrar si un webhook se reprodujo o si se emitieron varios eventos separados. Si el remitente incluye un contador de intentos, un número de entrega o un hash de la solicitud, guárdalo en los logs y en tu base de datos.
Construye una pequeña tabla comparativa si hace falta. Tres columnas bastan para una primera revisión: el identificador del payload, los metadatos de entrega y la acción de negocio realizada. Cuando el mismo ID de evento aparece dos veces, pero tu sistema solo actuó una vez, el reintento puede ser inofensivo. Cuando el mismo ID de evento aparece dos veces y tu sistema actuó dos veces, tienes una brecha de deduplicación.
| Campo | Qué te dice | Pista común |
|---|---|---|
| ID de evento | Si el evento del webhook es el mismo | Mismo ID, entrega repetida |
| ID de entrega | Qué intento de transporte llegó hasta ti | Distintos IDs de entrega, mismo evento |
| Contador de intentos | Cuántos intentos hizo el remitente | Número mayor después de un timeout |
| Firma | Si el cuerpo cambió durante el tránsito | Un desajuste sugiere un payload alterado |
Las señales de un duplicado real suelen ser aburridas, y eso es bueno. Mismo payload, mismos IDs, misma acción, entrega repetida. Las señales de eventos separados son más confusas: marcas de tiempo cercanas, contenido similar, pero IDs distintos o registros de origen distintos. Esa es la diferencia entre un problema de reintentos y un problema de producto.
¿Por qué los reconocimientos lentos suelen disparar entregas duplicadas?
La mayoría de los remitentes de webhooks esperan una respuesta 2xx rápida. Si tu servidor tarda 8 segundos, agota el tiempo a los 10 o devuelve un reset de conexión, el remitente puede no saber si el mensaje se procesó. Entonces reintenta. Desde su punto de vista, reintentar es más seguro que perder el evento.
Por eso una entrega puede tener éxito y aun así ser reintentada. La red puede fallar después de que tu app ya haya guardado el registro, o la respuesta puede retrasarse lo suficiente como para que el remitente asuma un fallo. Un solo response tardío basta. El remitente no tiene visibilidad perfecta de tu estado interno.
Una consulta lenta a la base de datos es suficiente para iniciar la cadena. También un contenedor frío, un hilo bloqueado o una cola que espera antes de devolver éxito. Si el endpoint del webhook hace trabajo pesado antes de reconocer la recepción, los mensajes duplicados se vuelven más probables. Eso es un problema de transporte, no de contenido.
Si quieres un patrón relacionado, el artículo sobre webhooks de correo para emails transaccionales cubre la misma idea en el manejo de eventos de email, donde el timing y el acuse de recibo determinan qué se entrega después.
¿Qué pasa si tu receptor procesó el evento pero aun así devolvió un fallo?
Este es especialmente desagradable. El webhook puede crear el pedido, enviar la notificación o actualizar el registro del cliente, y luego lanzar una excepción al construir la respuesta. El remitente ve un fallo. Reintenta. Tu sistema ahora tiene dos efectos secundarios de un solo evento, y los logs pueden no coincidir sobre qué paso falló primero.
Por eso los fallos parciales requieren atención especial. Un handler que guarda el mensaje y luego se cae antes de devolver 2xx puede haber hecho ya el trabajo real. El remitente, ajeno a ese hecho, hace lo que estaba programado para hacer. Si te preguntas por qué los reintentos de webhooks están causando mensajes duplicados, esta es una de las respuestas más comunes.
Revisa el flujo de código después del efecto secundario, no solo antes. ¿El handler escribió en la base de datos y luego falló en una llamada de métricas? ¿Publicó en una cola y luego expiró mientras formateaba JSON? ¿Envió un correo saliente y luego lanzó un error de validación? Los fallos pequeños pueden tener grandes efectos de duplicación.
¿Cómo detienes los duplicados provocados por reintentos sin perder eventos?
La idempotencia es la respuesta práctica. Guarda una clave única para cada evento y rechaza los repetidos antes de que puedan disparar una segunda acción. Esa clave puede ser el ID de evento, un ID de entrega del proveedor o una combinación de origen y hash del mensaje. Lo importante es que el mismo webhook se asocie al mismo resultado almacenado.
Haz la comprobación de deduplicación y la escritura en un solo paso atómico, si puedes. Si la comprobación ocurre primero y el insert después, dos workers pueden competir y ambos creer que llegaron primero. Una restricción única en la base de datos suele ser más simple que una caché en memoria personalizada, y sobrevive a reinicios. Aquí importan las pequeñas decisiones de diseño.
Usa una ventana corta de deduplicación solo cuando la política de reintentos del remitente sea corta y bien conocida. Si el proveedor reintenta durante horas, una caché de 5 minutos no basta. Si el evento puede llegar días después, tu almacén de deduplicación tiene que durar más que tu memoria del incidente.
Para equipos que gestionan tanto la entrega de eventos como la comunicación con clientes, guía de configuración de autenticación de correo es un complemento útil, porque la misma mentalidad aplica: confirma la identidad primero, actúa después y no confíes en una sola señal de forma aislada.
Envía la respuesta 2xx solo después de que el evento quede guardado de forma segura. Eso no significa que el flujo de negocio completo deba terminar antes del acuse. Significa que el receptor debe conservar el evento en un lugar duradero y luego procesarlo de forma asíncrona. Así el remitente ve éxito una sola vez, mientras tu worker puede reintentar con seguridad sin volver a aceptar el mismo evento.
¿Cuándo deberías aumentar la visibilidad sobre los intentos repetidos de webhook?
Registra los intentos repetidos desde el primer día. No esperes a que un usuario lo reporte. Una simple línea de log con ID de evento, ID de entrega, número de intento, código de respuesta y tiempo de procesamiento puede revelar una tormenta de reintentos antes de que se propague a correos, facturas o mensajes de texto. Una alerta a tiempo vale más que diez tickets de soporte después.
Configura una alerta cuando el mismo ID de evento aparezca más de una vez en una ventana corta, o cuando una sola fuente envíe un pico de reintentos después de un despliegue. Ese pico puede significar timeouts, certificados caducados, un deploy defectuoso o una dependencia aguas abajo que se ralentizó lo suficiente como para disparar reintentos. Cuanto antes veas el patrón, menos mensajes duplicados tendrás que limpiar.
Vigila tanto al receptor como al remitente. Si el panel del proveedor muestra 7 intentos pero los logs de tu aplicación solo 2, los 5 que faltan pueden ser fallos a nivel de red. Si los logs de tu aplicación muestran 7 eventos aceptados para un solo ID, el problema está dentro de tu ruta de deduplicación. En cualquier caso, el número te dice dónde mirar después.
Y si los duplicados están vinculados a alertas o notificaciones más que a webhooks por sí solos, la misma disciplina se aplica a la mensajería posterior, especialmente cuando un segundo sistema reacciona al primero sin comprobar si el primer mensaje ya se procesó.
En esta página
← Todos los artículosUn clic. Nos dice qué escribir a continuación.
No hay calificaciones aún — la tuya sería la primera.
Comentarios
Los comentarios se leen antes de aparecer.