
Soixante conteneurs sur un seul serveur
Une machine bare-metal exécute des dizaines à des centaines de conteneurs Hoody. La dédupplication KSM et BTRFS rend le coût marginal quasi nul.
Stripe POST le corps de l'événement vers un chemin de pipe avec ?n=12. Douze abonnés font GET sur le même chemin avec ?n=12. Le pipe retient le message jusqu'à ce que tout le monde soit connecté, puis diffuse aux douze à la fois. Pas de broker, pas de consumer group, pas de DLQ.
Hoody Pipe, c'est du streaming HTTP avec un mode multi-récepteurs. Ajoutez ?n=N aux URLs de l'expéditeur et du récepteur, et le pipe attend que N lecteurs s'attachent, puis miroite le corps à tous simultanément. Les lents ralentissent leur propre connexion — les rapides continuent à couler.
Votre endpoint Stripe transmet le corps de l'événement directement à /api/v1/pipe/billing?n=12. La connexion bloque pendant que le pipe attend que les douze récepteurs s'assemblent.
Chaque abonné est une boucle curl dans un conteneur, qui fait GET sur le même chemin avec ?n=12. Le pipe retient le corps en mémoire jusqu'à ce que le douzième lecteur se connecte — pas de file d'attente sur disque, rien à vider.
Une fois tout le monde connecté, le corps est diffusé aux douze à la fois. Un lecteur lent applique la backpressure à son propre socket ; les autres continuent. Quand le dernier lecteur se déconnecte, le pipe oublie le message.
# 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.Même URL, même chaîne de requête, des deux côtés. La connexion de l'expéditeur est le broker ; les connexions des lecteurs sont le consumer group. La backpressure est par socket, pas par topic, parce qu'il n'y a pas de topic — il y a un seul corps en vol et douze sockets qui tirent dessus.
Ajouter un abonné, c'est un curl de plus dans un conteneur de plus. En retirer un, c'est tuer le curl. Pas de config de broker, pas de rééquilibrage de consumer group, pas de DLQ à vider — la topologie du cluster, c'est juste les processus qui tournent en ce moment.
Le pipe ne suit pas qui est abonné. Il attend simplement n connexions par événement. Augmentez n des deux côtés et le prochain événement attend le nouvel effectif. Aucun état d'appartenance à corrompre parce qu'il n'y a pas d'appartenance.
Chaque ligne ci-dessous est une catégorie de travail qui disparaît quand le broker est le protocole. Aucune infrastructure à provisionner, aucune abstraction à apprendre — juste curl et ?n.
Pas de SQS, pas de cluster Kafka, pas d'exchange RabbitMQ. Le pipe est la file, et il vit pour un message à la fois.
Pas d'offsets, pas de commits, pas de rééquilibrages. Le pipe retient le corps jusqu'à ce que n sockets s'attachent — c'est tout le modèle de coordination.
Si l'expéditeur se déconnecte sans n lecteurs prêts, le pipe expire (TTL de 5 min) et Stripe réessaie. Pas de bucket de messages empoisonnés à surveiller.
Les abonnés sont des boucles curl. Les expéditeurs sont curl. Le protocole est HTTP. Tout ce qui peut frapper une URL peut rejoindre le cluster.
Un lecteur lent ralentit sa propre connexion. Les onze autres continuent à diffuser à pleine vitesse. Pas de blocage en tête de ligne sur la flotte.
Le corps disparaît au moment où le dernier lecteur se déconnecte. Pas de politique de rétention à définir, pas de log-compaction à planifier, pas de job de suppression-sur-demande RGPD à écrire.
Douze abonnés, une URL, pas de broker.
Les brokers ci-dessous sont les choses que vous installiez avant que le fan-out HTTP ne devienne un paramètre de requête. Le côté droit est ce qui les remplace — un chemin, un n, et douze processus curl qui ne savent pas qu'ils forment un cluster.
Douze récepteurs font GET sur le même chemin avec le même n. Le pipe est le broker — et oublie le message à la seconde où le dernier lecteur raccroche.
Si vous tendez la main vers l'un de ceux-ci pour diffuser un webhook à N consommateurs, le modèle pipe fait le même travail en deux invocations curl — expéditeur d'un côté, récepteurs de l'autre.
Le fan-out pour lequel vous écriviez un sprint est désormais un paramètre de requête. Ajoutez ?n=12 et expédiez.