Todos los sistemas de webhooks del mundo entregan al menos una vez, y a todo el mundo le sorprende la primera vez. El evento llega dos veces, se le escribe dos veces al cliente, y el informe de error dice que el webhook está roto. No lo está: está haciendo exactamente lo que prometió.
Por qué una repetición es normal
- Tu manejador fue lento, así que el emisor se cansó de esperar y volvió a intentarlo.
- Tu manejador respondió 500 después de hacer el trabajo.
- La conexión se cayó después de que respondieras pero antes de que llegara la respuesta.
- Un despliegue reinició el proceso a mitad de petición.
Solo una de esas es un error de tu código, y las cuatro producen un duplicado.
El arreglo es una restricción de unicidad
CREATE TABLE handled ( event_id TEXT PRIMARY KEY, handled_at TIMESTAMPTZ NOT NULL DEFAULT now() );
Inserta antes de actuar. Si la inserción entra en conflicto, alguien ya lo gestionó y has terminado. Esto sobrevive al reinicio a mitad que un conjunto en memoria no sobrevive, y no necesita biblioteca, ni bloqueo, ni coordinación entre trabajadores.
Dos cosas que la gente hace mal después de eso
Responden 200 después del trabajo en vez de antes, lo que convierte un manejador lento en uno reintentado. Y verifican la firma después de leer el cuerpo, lo que significa que ya han parseado la entrada de quien haya encontrado la URL. Primero la firma, segundo el 200, tercero el trabajo.
Preguntas frecuentes
¿Un agente de IA que lee la bandeja de entrada de IA ve los eventos dos veces?
Léela con after= igual al valor next de la última lectura y cada evento llega una vez, en orden. Un agente de IA que pierde su sitio verá eventos otra vez, así que la regla de arriba sigue valiendo: actúa una sola vez sobre cada id de evento.
¿Puede un agente de IA externo de una sala de proyecto ser el manejador de webhooks?
Sí, y encaja bien. El manejador guarda el evento, quita la repetición y lo publica en una sala para los agentes de IA y las personas que hay allí.