Ir al contenido
use-cases / the-webhook-fan-out-you-didnt-have-to-build / hero
PIPE · FAN-OUT HTTP

El fan-out de webhooks que no tuviste que construir

Stripe hace POST del cuerpo del evento a una ruta de pipe con ?n=12. Doce suscriptores hacen GET a la misma ruta con ?n=12. El pipe retiene el mensaje hasta que todos están conectados, y luego lo transmite a los doce a la vez. Sin broker, sin consumer group, sin DLQ.

use-cases / the-webhook-fan-out-you-didnt-have-to-build / mechanism

Una URL. Doce lectores. Backpressure por conexión.

Hoody Pipe es streaming HTTP con un modo multi-receptor. Añade ?n=N a las URLs del emisor y del receptor y el pipe espera hasta que se conecten N lectores, luego replica el cuerpo a todos ellos a la vez. Los lentos limitan su propia conexión — los rápidos siguen fluyendo.

01PASO 01 · ENTRADA

Stripe hace POST al pipe

Tu endpoint de Stripe reenvía el cuerpo del evento directo a /api/v1/pipe/billing?n=12. La conexión se bloquea mientras el pipe espera a que se reúnan los doce receptores.

02PASO 02 · ENSAMBLAR

Doce suscriptores se conectan

Cada suscriptor es un bucle de curl en un contenedor, haciendo GET a la misma ruta con ?n=12. El pipe mantiene el cuerpo en memoria hasta que se conecta el duodécimo lector — sin cola en disco, nada que vaciar.

03PASO 03 · STREAM

Fan-out, y luego olvidar

Una vez conectados todos, el cuerpo se transmite a los doce a la vez. Un lector lento aplica backpressure a su propio socket; los demás siguen. Cuando el último lector se desconecta, el pipe olvida el mensaje.

stripe-webhook.sh
# Sender side — your Stripe webhook handler.
# Pipe holds the body until 12 readers are attached.
curl -X POST "https://api.hoody.com/api/v1/pipe/billing?n=12" \
  -H "Authorization: Bearer $HOODY_TOKEN" \
  -H "Content-Type: application/json" \
  --data-binary "@stripe-event.json"

# Receiver side — one of twelve subscriber containers.
# Same path, same n. Streams the event body when fan-out is ready.
curl -N "https://api.hoody.com/api/v1/pipe/billing?n=12" \
  -H "Authorization: Bearer $HOODY_TOKEN" | ./billing-handler.sh

# n must match on both ends — mismatch returns 400.
# Default n=1 is point-to-point. n=12 is fan-out for twelve.

Misma URL, mismo query string, en ambos extremos. La conexión del emisor es el broker; las conexiones de los lectores son el consumer group. El backpressure es por socket, no por topic, porque no hay topic — hay un cuerpo en vuelo y doce sockets tirando de él.

use-cases / the-webhook-fan-out-you-didnt-have-to-build / fleet

Los suscriptores van y vienen como procesos

Añadir un suscriptor es un curl más en un contenedor más. Quitar uno es matar el curl. No hay configuración de broker, ni rebalanceo de consumer group, ni DLQ que vaciar — la topología del cluster es simplemente lo que haya corriendo ahora mismo.

diff de suscriptores · últimos 5 minutosno se requiere rebalanceo
  • + AÑADIDOS
    WHKAUD
    dos contenedores nuevos arrancados
  • − ELIMINADOS
    MIX
    contenedor matado, curl terminado
  • = ESTABLES
    BILANLLOGFRDSUCSLACRMCDNNOT
    siguen en la misma ruta n=12

El pipe no rastrea quién está suscrito. Solo espera n conexiones por evento. Subes n en ambos extremos y el siguiente evento espera al nuevo aforo. No hay estado de membresía que corromper porque no hay membresía.

use-cases / the-webhook-fan-out-you-didnt-have-to-build / advantages

Lo que ya no tienes que operar

Cada línea de abajo es una categoría de trabajo que desaparece cuando el broker es el protocolo. Sin infraestructura que aprovisionar, sin abstracciones que aprender — solo curl y ?n.

  • Sin cola que aprovisionar

    Sin SQS, sin cluster Kafka, sin exchange RabbitMQ. El pipe es la cola, y vive un mensaje a la vez.

  • Sin contabilidad de consumer group

    Sin offsets, sin commits, sin rebalanceos. El pipe retiene el cuerpo hasta que se conectan n sockets — ese es todo el modelo de coordinación.

  • Sin DLQ que vaciar

    Si el emisor se desconecta sin n lectores listos, el pipe expira (TTL de 5 min) y Stripe reintenta. Sin cubo de mensajes envenenados que cuidar.

  • Sin SDK por lenguaje

    Los suscriptores son bucles de curl. Los emisores son curl. El protocolo es HTTP. Cualquier cosa que pueda golpear una URL puede unirse al cluster.

  • Backpressure por socket

    Un lector lento limita su propia conexión. Los otros once siguen transmitiendo a velocidad máxima. No hay bloqueo de cabeza de línea en toda la flota.

  • Olvidadizo por defecto

    El cuerpo desaparece en cuanto el último lector se desconecta. Sin política de retención que fijar, sin compactación de logs que programar, sin job de borrado bajo petición de GDPR que escribir.

use-cases / the-webhook-fan-out-you-didnt-have-to-build / punchline

Doce suscriptores, una URL, sin broker.

Los brokers de abajo son las cosas que solías instalar antes de que el fan-out HTTP fuera un parámetro de query. El lado derecho es lo que las reemplaza — una ruta, un n y doce procesos curl que no saben que son un cluster.

LO QUE NO CORRES
  • AWS Lambda + SQS/SNS
  • Apache Kafka
  • Exchanges de RabbitMQ
  • Routers de webhook a medida
LO QUE LLAMAS EN SU LUGAR
POST /api/v1/pipe/billing?n=12

Doce receptores hacen GET a la misma ruta con el mismo n. El pipe es el broker — y olvida el mensaje en el segundo en que el último lector cuelga.

use-cases / the-webhook-fan-out-you-didnt-have-to-build / replaces

Qué reemplaza esto

Si recurres a alguno de estos para difundir un webhook a N consumidores, el modelo del pipe está haciendo el mismo trabajo en dos invocaciones de curl — emisor en un lado, receptores en el otro.

  • AWS Lambda + SQS/SNSBroker por topic, IAM por suscriptor
  • Apache KafkaCluster, ZooKeeper/KRaft, consumer groups
  • Exchanges de RabbitMQBindings, vhosts, UI de mgmt por entorno
  • Routers de webhook a medidaServicio que mantener, reintentos que inventar
  • Servicios Pub/SubCobro por mensaje, lock-in con GCP/AWS
  • Plugins de fan-out HTTPPlugin de gateway por stack, sin backpressure
use-cases / the-webhook-fan-out-you-didnt-have-to-build / cta

El fan-out al que solías dedicar un sprint ahora es un parámetro de query. Añade ?n=12 y despliega.

use-cases / the-webhook-fan-out-you-didnt-have-to-build / related

Lee los otros