
Sechzig Container auf einem Server
Eine Bare-Metal-Box führt Dutzende bis Hunderte von Hoody-Containern aus. KSM und BTRFS-Dedup machen die Marginalkosten nahezu null.
Stripe POSTet den Event-Body an einen Pipe-Pfad mit ?n=12. Zwölf Subscriber GETten denselben Pfad mit ?n=12. Die Pipe hält die Nachricht, bis alle verbunden sind, und streamt sie dann gleichzeitig an alle zwölf. Kein Broker, keine Consumer Group, keine DLQ.
Hoody Pipe ist HTTP-Streaming mit einem Multi-Receiver-Modus. Hänge ?n=N an Sender- und Receiver-URLs und die Pipe wartet, bis sich N Reader verbinden — dann spiegelt sie den Body gleichzeitig an alle. Die langsamen drosseln ihre eigene Verbindung — die schnellen fließen weiter.
Dein Stripe-Endpoint leitet den Event-Body direkt an /api/v1/pipe/billing?n=12 weiter. Die Verbindung blockiert, während die Pipe darauf wartet, dass sich die zwölf Receiver versammeln.
Jeder Subscriber ist eine curl-Schleife in einem Container, die denselben Pfad mit ?n=12 GETtet. Die Pipe hält den Body im Speicher, bis sich der zwölfte Reader verbindet — keine On-Disk-Queue, nichts zu flushen.
Sobald alle verbunden sind, streamt der Body gleichzeitig an alle zwölf. Ein langsamer Reader übt Backpressure auf seinen eigenen Socket aus; die anderen ziehen weiter. Wenn der letzte Reader trennt, vergisst die Pipe die Nachricht.
# 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.Dieselbe URL, derselbe Query-String, beide Enden. Die Verbindung des Senders ist der Broker; die Verbindungen der Reader sind die Consumer Group. Backpressure ist pro Socket, nicht pro Topic, weil es kein Topic gibt — es gibt einen In-Flight-Body und zwölf Sockets, die daran ziehen.
Einen Subscriber hinzuzufügen ist ein curl mehr in einem Container mehr. Einen zu entfernen heißt, das curl zu killen. Es gibt keine Broker-Config, kein Consumer-Group-Rebalancing, keine DLQ zu drainen — die Cluster-Topologie ist einfach das, was gerade an Prozessen läuft.
Die Pipe trackt nicht, wer subscribed ist. Sie wartet einfach pro Event auf n Verbindungen. Setz n auf beiden Seiten hoch und das nächste Event wartet auf die neue Anzahl. Es gibt keinen Membership-State, der korrumpieren könnte, weil es keine Membership gibt.
Jede Zeile unten ist eine Kategorie von Arbeit, die verschwindet, wenn das Protokoll der Broker ist. Keine Infrastruktur zu provisionieren, keine Abstraktionen zu lernen — nur curl und ?n.
Kein SQS, kein Kafka-Cluster, keine RabbitMQ-Exchange. Die Pipe ist die Queue und sie lebt nur für eine Nachricht.
Keine Offsets, keine Commits, keine Rebalances. Die Pipe hält den Body, bis n Sockets sich verbinden — das ist das gesamte Coordination-Modell.
Wenn der Sender trennt, bevor n Reader bereit sind, läuft die Pipe in einen Timeout (5-min TTL) und Stripe versucht es erneut. Kein Poison-Message-Bucket zum Babysitten.
Subscriber sind curl-Schleifen. Sender sind curl. Das Protokoll ist HTTP. Alles, was eine URL aufrufen kann, kann dem Cluster beitreten.
Ein langsamer Reader drosselt seine eigene Verbindung. Die anderen elf streamen weiter mit voller Geschwindigkeit. Es gibt kein Head-of-Line-Blocking über die Flotte hinweg.
Der Body ist weg in dem Moment, in dem der letzte Reader trennt. Keine Retention-Policy zu setzen, kein Log-Compaction zu schedulen, kein GDPR-Delete-on-Request-Job zu schreiben.
Zwölf Subscriber, eine URL, kein Broker.
Die Broker unten sind die Dinge, die du früher installiert hast, bevor HTTP-Fan-out ein Query-Parameter war. Rechts steht, was sie ersetzt — ein Pfad, ein n und zwölf curl-Prozesse, die nicht wissen, dass sie ein Cluster sind.
Zwölf Receiver GETten denselben Pfad mit demselben n. Die Pipe ist der Broker — und vergisst die Nachricht in der Sekunde, in der der letzte Reader auflegt.
Wenn du zu einem dieser Dinge greifst, um einen Webhook an N Consumer zu broadcasten, macht das Pipe-Modell denselben Job in zwei curl-Aufrufen — Sender auf der einen Seite, Receiver auf der anderen.
Das Fan-out, für das du früher einen Sprint geschrieben hast, ist jetzt ein Query-Parameter. Häng ?n=12 dran und ship.