Webhook Delivery es un motor que acepta eventos, crea una entrega independiente por cada destino suscrito y procesa los envíos fuera de la petición original. El proyecto aborda un problema habitual de las integraciones: el sistema receptor puede estar lento, temporalmente caído o responder con un error que requiere intervención.
El objetivo no era limitarse a ejecutar peticiones HTTP en segundo plano. La entrega debía conservarse ante reinicios, registrar cada intento y permitir investigar o recuperar los fallos sin perder el contexto original.
Separar aceptación y entrega#
La API recibe un evento, identifica los endpoints activos y persiste el evento, las entregas y una entrada de outbox en una sola transacción de PostgreSQL. Después responde con 202 Accepted. Esto confirma que el trabajo fue aceptado, no que todos los receptores ya lo hayan procesado.
Un publicador mueve el trabajo durable hacia Redis Streams. Los workers reclaman las entregas y realizan las peticiones HTTP firmadas. Si Redis deja de estar disponible, los eventos siguen almacenados en PostgreSQL y el backlog puede reenviarse cuando el servicio se recupera.
Esta separación evita que la latencia del receptor se propague hacia quien publica el evento. También permite que un destino falle sin bloquear a los demás participantes del fan-out.
Política explícita de fallos#
Cada resultado se clasifica antes de decidir la siguiente transición:
- Las respuestas
2xxcompletan la entrega. - Los timeouts, errores de red,
408,425,429y5xxprograman un nuevo intento. - Los errores permanentes terminan la ejecución automática.
- Al agotarse el presupuesto de reintentos, la entrega pasa a
dead_letter.
Los reintentos usan backoff exponencial con jitter y quedan programados en la base de datos. Los workers no permanecen dormidos esperando el próximo intento. Una recuperación manual abre un nuevo presupuesto sin eliminar el historial anterior, de modo que el operador puede ver tanto el fallo original como el resultado posterior.
Seguridad y consistencia#
Cada endpoint recibe un secreto al crearse. El worker firma los bytes enviados con HMAC-SHA256 e incluye identificadores estables para que el receptor pueda validar la autenticidad y deduplicar entregas repetidas.
La garantía es at-least-once: el sistema prioriza no perder trabajo, por lo que el receptor debe tratar el identificador del webhook como clave de idempotencia. La firma autentica el cuerpo, pero no lo cifra.
En producción, las URLs requieren HTTPS, una lista explícita de hosts y validación DNS para bloquear destinos privados o reservados. Los redirects y proxies de entorno están desactivados. La documentación también deja registrada una limitación: la dirección conectada no queda fijada después de la prevalidación DNS, por lo que una instalación real necesita controles de salida adicionales contra DNS rebinding.
Observabilidad y recuperación#
El dashboard permite filtrar entregas por estado y tipo de evento, revisar cada intento y solicitar una nueva entrega. La API expone métricas de volumen, estados, reintentos, tasa de éxito y percentiles de latencia. Los IDs de correlación conectan la petición inicial con los eventos y logs de los workers.
Los claims usan tokens y leases para impedir que un worker interrumpido sobrescriba un resultado más reciente. El outbox y un proceso de reconciliación recuperan trabajo después de fallos de Redis o mensajes perdidos. La base de datos, y no el stream, conserva la autoridad sobre el estado.
Evidencia de carga#
El repositorio incluye un runner aislado que crea sus propios recursos, inyecta fallos y limpia el entorno al terminar. En una ejecución documentada de 10,000 eventos y 20,000 entregas, el sistema terminó con 19,600 entregas correctas y 400 fallos terminales intencionales. El backlog observado llegó a 12,420 entregas y terminó en cero.
La ejecución, sus parámetros, el gráfico de la cola y las invariantes comprobadas están publicados como experimento reproducible en el Lab de Webhook Delivery. El código y los artefactos originales permanecen disponibles en el repositorio del proyecto.
Esas cifras describen una prueba local controlada, no un SLA de producción. La latencia incluye cola y reintentos, y el escenario incorpora respuestas permanentes y transitorias de forma deliberada.
Resultado#
El proyecto convierte una operación HTTP frágil en un flujo durable e investigable. FastAPI ofrece la superficie de gestión y publicación; PostgreSQL mantiene la verdad transaccional; Redis Streams distribuye el trabajo; y los workers aplican las políticas de entrega, seguridad y recuperación.
El resultado demuestra que la confiabilidad de webhooks no depende únicamente de volver a intentar. Requiere definir qué se persiste, quién posee cada transición, cómo se recupera el trabajo interrumpido y qué evidencia queda disponible cuando algo falla.

