Zum Inhalt springen
TypFreigeschaltet
PhaseFleet
SchwierigkeitMittel
AufgabeKostenoptimierung
FürDevOps & Infra
FürDev Teams
ServicesPipe
ServicesContainers
Warum HoodyHTTP-nativ
Warum HoodyContainer-Ökonomie
TypFreigeschaltet
PhaseFleet
SchwierigkeitMittel
AufgabeKostenoptimierung
FürDevOps & Infra
FürDev Teams
ServicesPipe
ServicesContainers
Warum HoodyHTTP-nativ
Warum HoodyContainer-Ökonomie
TypFreigeschaltet
PhaseFleet
SchwierigkeitMittel
AufgabeKostenoptimierung
FürDevOps & Infra
FürDev Teams
ServicesPipe
ServicesContainers
Warum HoodyHTTP-nativ
Warum HoodyContainer-Ökonomie
TypFreigeschaltet
PhaseFleet
SchwierigkeitMittel
AufgabeKostenoptimierung
FürDevOps & Infra
FürDev Teams
ServicesPipe
ServicesContainers
Warum HoodyHTTP-nativ
Warum HoodyContainer-Ökonomie
PIPE · CI · KOSTEN OPTIMIEREN

Ein CI-Cache, der nur aus zwei curl-Befehlen besteht

Der erste Job in deiner Pipeline tart node_modules und pipet sie in eine Hoody-URL. Zwanzig nachgelagerte Jobs holen dieselbe URL per curl und entpacken. Mit ?n=20 wartet der Producer, bis sich alle zwanzig Worker verbunden haben, und streamt dann einmal — gefannt out an alle. Kein S3-Bucket, keine Cache-Action, keine Egress-Rechnung.

Pipe-Docs lesen

Die ganze Mechanik in zwei Shell-Zeilen

Es gibt keine Client-Library, keinen Daemon, kein SDK. Der Producer streamt seinen Tarball in PUT /pipe/cache?n=20. Jeder Worker streamt ihn aus GET /pipe/cache?n=20 wieder raus. Die Pipe hält die Bytes nur, während sie in Flight sind — niemals auf der Disk.

PUT · PRODUCEREINMAL PRO BUILD AUSFÜHREN

Cache erzeugen

$tar c node_modules|zstd|curl -T -
https://hoody.com/pipe/cache?n=20
# blocks until 20 receivers connect, then streams once

tar packt node_modules; zstd komprimiert on the fly; curl PUTtet die Bytes direkt in den Pipe-Pfad. Kein Tempfile, kein upload-artifact-Step, keine Bucket-Credentials.

GET · CONSUMERAUF JEDEM WORKER AUSFÜHREN

Cache konsumieren

$curlhttps://hoody.com/pipe/cache?n=20
| zstd -d | tar x
# fan-out: every worker gets an identical copy

Jeder Test-Worker GETtet dieselbe URL, dekomprimiert und entpackt in sein Working Directory. Langsame Worker üben Backpressure auf den Producer aus, blockieren aber nicht die schnelleren.

DIE GESAMTE COORDINATION-SURFACE?n=20

Ein Query-Parameter. Producer und Consumer einigen sich auf dasselbe n. Die Pipe hält den Upload, bis exakt so viele Receiver verbunden sind, und öffnet dann die Schleusen.

Wofür du nicht mehr zahlst

CI-Caching war früher eine Steuer: Storage, den du morgen überschreibst, Egress jedes Mal, wenn ein Worker zieht, Engineering-Zeit für die Macken der Cache-Action. Die Pipe streicht alle drei Posten auf einmal.

Kein Bucket. Keine Egress-Rechnung.

Es gibt keinen S3-Bucket, weil es keinen Storage gibt. Die Pipe vergisst die Bytes in der Sekunde, in der der Transfer endet — also gibt es nichts, wofür man pro GB-Monat oder pro GB-Out abrechnen könnte. Der Cache ist kein Kostenposten mehr.

Keine Cache-Action-Macken

Keine YAML-codierten Keys, kein save-cache/restore-cache-Split, kein Debugging, warum ein Cache-Hit nicht auf dem richtigen Runner passiert ist. Nur curl. Dieselben zwei Zeilen laufen auf GitHub Actions, BuildKite, Jenkins, deinem Laptop oder einem Cron-Container.

Keine Key-Kollisionen über Branches

Branches nutzen einfach unterschiedliche Pfade. /pipe/cache/main, /pipe/cache/feat-x, /pipe/cache/PR-742. Nichts zu invalidieren. Nichts zu evicten. Wenn der Branch stirbt, wird sein Pfad nicht mehr abgefragt — und das ist der gesamte Lifecycle.

Die Kostenform, vorher und nachher

Bei einem realen Workload — node_modules um die 800 MB, zwanzig parallele Test-Worker, hundert CI-Runs pro Tag — ist der Großteil der Rechnung Egress, nicht Storage.

S3 + GH ACTIONS CACHE

20× Egress

Jeder der zwanzig Worker zieht den Cache aus S3. Zwanzig Downloads eines 800-MB-Tarballs sind 16 GB Egress pro CI-Run. Der Bucket selbst ist der einfache Teil — der Egress ist es, was sich aufaddiert.

VS
HOODY PIPE · ?n=20

1× Transfer

Der Producer streamt die 800 MB einmal. Die Pipe fanntoutet die Bytes in Flight an alle zwanzig Receiver. Ein Transfer durch die Leitung, kein Per-Receiver-Multiplikator, keine Storage-Rechnung.

Zahlen sind illustrativ für einen typischen Node-Monorepo-Cache. Tatsächliche Einsparungen hängen von Tarball-Größe, Worker-Fan-out und dem Egress-Preis ab, den dein Provider aus der Cache-Region berechnet. Die Form — linear vs. konstant in der Worker-Anzahl — bleibt invariant.

Die Cache-Schicht ist HTTP. War sie immer. Wir haben es nur nicht gemerkt.

Caches waren nie Storage. Es ging darum, dieselben Bytes ohne Rebuild an N Worker zu kriegen. HTTP macht das längst — sobald du eine URL an eine bekannte Anzahl von Receivern fan-outten lässt. Der Bucket war ein Workaround für das Fan-out, das wir nicht hatten.

BYTES

Einmal streamen, fan-outten

Ein PUT, n GETs, identische Bytes. Backpressure ist pro Receiver, damit der langsame Worker die schnellen nicht ausbremst.

PUT /pipe/cache?n=20
TIME

Lebt nur in Flight

Die Pipe hält die Bytes für den Transfer und vergisst sie, wenn er endet. Nichts zu evicten, nichts zu lifecyclen, nichts zu backupen.

TTL ≤ 5 min · dann evicted
PATH

Branches sind Pfade

Jeder Branch wählt seinen eigenen Pfad. Kein gemeinsamer Keyspace, keine Kollisionen. Der Pfad ist der Cache-Key und die URL zugleich.

/pipe/cache/[branch]
Pipe-API lesen

Was das ersetzt

Die meisten CI-Caches lösen dasselbe Problem: denselben Tarball an N Worker bringen. Sie tun es über Storage und Egress. Die Pipe tut es über die Leitung.

  • AWS S3 (Cache-Bucket + Egress)Storage, den du morgen überschreibst + Per-Pull-Egress
  • GitHub Actions CacheYAML-Keys, Runner-spezifische Macken, 10-GB-Limit
  • BuildJet / Garnix CI CachesSchneller, trotzdem pro Vendor, trotzdem pro Byte
  • Bazel Remote CacheHervorragend, wenn du voll auf Bazel setzt; schwer, wenn nicht
  • Turborepo Remote CacheVercel-gehostet, monorepo-geformt, opinionated
  • Earthly Satellite CacheNoch ein Daemon, noch ein Bucket, noch eine Rechnung
  • Eigene rsync-CachesEine NFS-Box und ein SSH-Key, den jeder vergisst zu rotieren

Zwei curl-Befehle. Eine URL. Zwanzig Worker versorgt.

Pipe-Docs lesen

Lies die anderen