
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.
Du fährst eine achtstündige Migration. Fünf Leute wollen einen Status, ohne einen Receiver-Slot zu belegen oder den Stream zu unterbrechen. Hänge ?progress an die Pipe-URL. Wer sie öffnet, bekommt ein Live-HTML-Dashboard — übertragene Bytes, aktuelle Geschwindigkeit, ETA, Statusübergänge. Die Migration läuft mit voller Geschwindigkeit, egal wie viele zuschauen.
?progress ist ein Side-Channel-Read. Er belegt nie einen Receiver-Slot, erzeugt nie Backpressure, berührt nie die Bytes. Die Migration läuft mit voller Bandbreite, egal wie viele zuschauen.
Sie pastet die Pipe-URL mit ?progress in ihren Phone-Browser. Das HTML-Dashboard erscheint sofort — state: waiting, 0% — keine Installation, kein Login, kein Receiver-Slot verbraucht.
SSE schickt ein state: streaming Event. Der Fortschrittsbalken springt auf 22%, Bytes ticken auf, MB/s stabilisiert sich bei 118. Das Dashboard aktualisiert sich alle 250 ms ohne ein einziges Seitenladung.
Sie schließt den Tab. Ihre Spectator-Verbindung fällt weg. Die Migration merkt das nicht — sie war nie im Datenpfad. Sender und ihr one real Receiver machen weiter.
Sie öffnet die URL wieder beim Sonnenaufgang. Das Dashboard zeigt ein done Event: 7,6 GB transferiert, 8h 2m, keine Fehler. Serverseitiger State überlebt die Aktualisierung — Spätzünder sehen immer die Final Line.
Sie leitet die URL an den Team Slack weiter. Drei Engineers öffnen sie und sehen den gleichen done State. Kein Status-Thread zum Schließen, kein Grafana-Panel zum Demarkieren. Eine URL, fünf Zeugen, null Interruptions.
# 1. Sender — eight-hour migration. Same as always.
tar czf - /var/lib/postgres | curl -T - "$PIPE/api/v1/pipe/migration"
# 2. Receiver — the only client that matters for backpressure.
curl "$PIPE/api/v1/pipe/migration" | tar xzf - -C /restore
# 3. Boss opens the URL on her phone. HTML dashboard. No setup.
# => https://pipe.hoody.com/api/v1/pipe/migration?progress
# 4. You want SSE for a Slack bot? Same URL, different Accept.
curl -N -H "Accept: text/event-stream" \
"$PIPE/api/v1/pipe/migration?progress" \
| grep -E '^event: (progress|state|done)'
# event: state \n data: '{'"state":"streaming","receivers":1'}'
# event: progress \n data: '{'"bytes":5046464512,"mbps":118,"etaSec":840'}'
# event: done \n data: '{'"bytes":8160000000,"durationSec":28800'}'Drei SSE-Event-Typen. state für Übergänge (idle → waiting → streaming → complete), progress alle 250 ms während Bytes fließen (bytesTransferred, Speed, ETA), done einmal am Ende mit den finalen Stats. Bis zu fünfzig Spectators pro Pfad, jeder mit einem Fünf-Minuten-Verbindungs-Fenster.
?progress ist ein Side-Channel. Chef, Kolleg*in, externe Kund*in, On-Call — alle öffnen die gleiche URL. Keiner von ihnen berührt den Transfer. Alle sehen den gleichen Live-State.
Setzt ein Bookmark der URL auf ihrem Phone. Schaut zweimal täglich nach.
HTML-Dashboard, kein LoginCurl SSE in einen Slack-Webhook. Einzeiler-Statusbot.
text/event-stream, dieselbe URLEingebettet in eine öffentliche Statusseite. Pollt alle 30 s.
0 Receiver-Slots, voller Live-StateVerdrahtet mit PagerDuty über das done Event. Pingt wenn fertig.
event: done, ein-Schuss-TriggerDer Migration zuzuschauen ist eine eigene URL. Die Migration merkt nichts.
Jedes Team hat eine Methode, 'wie weit sind wir?' zu beantworten. Die meisten dieser Methoden kosten einen Service, der laufen muss, ein Dashboard, das verkabelt werden muss, oder einen Chat-Channel, den jemand babysitten muss. Ein Query-Parameter auf der Pipe-URL kostet nichts davon.
Schick die URL. Hör auf, Updates zu schicken.