top of page

Tausend Build-Läufe im Monat — und keiner davon kostet etwas ⚙️

Autorenbild: Marcel Dütscher
Marcel Dütscher
26. Juli
3 Min. Lesezeit

Korrektur vorweg. In der ersten Fassung dieses Artikels stand, unsere Build-Minuten bei GitHub seien aufgebraucht und deshalb sei ein Upgrade auf ein Pro-Konto fällig geworden. Das war falsch, und zwar auf eine Art, die ein einziger Blick in die Dokumentation aufgeklärt hätte: Für öffentliche Repositories sind GitHub-Build-Minuten kostenlos. Artefakte und Caches ebenfalls. Unser Repository ist seit Ende Mai öffentlich — wir haben also nie eine Minute bezahlt und werden es auch nicht. Statt den Text still zu korrigieren, schreiben wir ihn lieber neu und erzählen, was das Nachmessen ergeben hat. Das ist nämlich deutlich interessanter als die falsche Version.


Erst geraten, dann nachgesehen. Der Auslöser war ein Abend, an dem ein fertiger Pull Request im Browser lag und keine einzige Prüfung ansprang. Keine grünen Häkchen, nur Stille. Wir haben auf das Naheliegende getippt — „Kontingent alle" — und ein Pro-Konto genommen. Danach lief wieder alles, was die Vermutung bestätigt zu haben schien. Hat sie aber nicht: Die Stille hatte einen anderen Grund (ein Pull Request, den GitHub gerade nicht sauber mit dem Hauptzweig zusammenführen konnte, startet keine Prüfungen). Wir haben inzwischen die Abrechnungsdaten jedes einzelnen Laufs abgefragt. Antwort für jeden Lauf, auf jedem Betriebssystem: abrechenbare Zeit = 0 Millisekunden. Ein Konto darf man trotzdem gerne unterstützen — aber als Erklärung für dieses Repository taugt es nicht.


Was trotzdem stimmt: die Maschinerie ist gewachsen. Jeder Pull Request stößt eine kleine Fabrik an: Der komplette Server wird gebaut und seine Testsuite durchgerannt, Linter und Code-Analyse schauen drüber, CodeQL sucht nach Sicherheitslücken, Docker-Images für Spielserver, Portal, WorldHost und KI-Backend entstehen. Bei einem Release kommen Windows-, Linux- und macOS-Builds des Clients dazu, dazu die WebGL-Version fürs Browser-Spiel. Seit Ende Mai sind so 1.723 Build-Läufe zusammengekommen, 1.092 davon allein im Juli — bei 131 zusammengeführten Pull Requests in vier Wochen. Dass es zuletzt so viele wurden, hat übrigens tatsächlich mit der KI zu tun 😉: Das Projekt wird zu 100 % mit KI-Unterstützung entwickelt, und mit dem größeren Abo läuft schlicht mehr parallel. Nur ist die Währung eben nicht Geld, sondern Wartezeit.


Wo die Wartezeit hingeht. Über acht Tage gemessen: die normale Prüfstrecke (CI) 379 Minuten, die Sicherheitsanalyse CodeQL 230, die Release-Builds 126, der Rest ist Kleinkram. Ein einzelnes Release kostet rund 110 Minuten Rechenzeit, aufgeteilt auf WebGL (31,6), Docker-Image (19,4), macOS (13,7), Linux (13,7), das große Test-Tor (12,1), Windows (10,9) und das Zusammenpacken (7,2). Das ist die Zeit zwischen „fertig" und „bei euch installierbar".


Und jetzt das, was wirklich knapp ist: der Cache. Damit ein Build nicht jedes Mal bei null anfängt, legt GitHub Zwischenergebnisse ab — und dafür gibt es 10 GB pro Repository, egal wie öffentlich man ist. Bei uns liegen davon aktuell 5,3 GB in 63 Einträgen. Das Problem ist die Verteilung: Rund zwei Drittel davon sind Docker-Zwischenschichten, die bei jedem Lauf neu abgelegt werden — und die verdrängen ausgerechnet das, was am meisten bringen würde. Das ist der eigentliche Engpass, und der lässt sich mit keinem Abo der Welt wegkaufen.


Der schönste Fund war ein echter Bug. Unity legt beim Bauen einen riesigen Zwischenordner an (Library), dessen Wiederverwendung Minuten spart. Beim Nachmessen kam heraus: Für Windows, Linux und macOS wurde dieser Ordner nie gespeichert — die Builds versuchten brav, ihn wiederherzustellen, geschrieben hat ihn nie jemand. Und der Windows-Build hatte als einziger einen Cache-Schlüssel ohne Plattform-Kennung. Ergebnis: Er lud sich 1,7 GB WebGL-Zwischenstand herunter, den Unity dann pflichtbewusst wegwarf und alles neu importierte. Im Protokoll sieht man es schwarz auf weiß: 257 Sekunden Asset-Import statt 85 Sekunden im warmen Fall. Macht knapp neun verschenkte Minuten pro Release — weil in einem Schlüssel ein Wort fehlte.


Was noch aufgefallen ist. Unsere Testsuite läuft dreimal pro ausgeliefertem Commit (im Pull Request, nach dem Zusammenführen, und noch einmal beim Release). CodeQL prüft drei Sprachen bei jedem Pull Request, obwohl es gar keine Pflichtprüfung ist. Ein Cache für die .NET-Pakete fehlt komplett. Ein Emulator für fremde Prozessor-Architekturen wird eingerichtet, obwohl wir nur für eine bauen. Und 7,4 GB alte Build-Artefakte liegen mit der Standard-Aufbewahrung von 90 Tagen herum. Nichts davon ist dramatisch — zusammen ist es aber ein gutes Stück Lebenszeit.


Die Lehre ist dieselbe wie bei unserem Server. Damals hatten wir gemessen, dass die Hälfte des belegten Arbeitsspeichers gar nicht ans Spiel ging, sondern an Docker und das Monitoring. Diesmal war es noch peinlicher: Wir haben eine Rechnung angenommen, die es nie gab, und bezahlt, bevor wir nachgesehen haben. Messen statt raten — der Satz gilt anscheinend so lange, bis man ihn wirklich verinnerlicht hat. Die Aufräumarbeiten sind geplant, aber noch nicht umgesetzt; wenn sie laufen, erzählen wir, was sie gebracht haben. 🚀

Aktuelle Beiträge

Alle ansehen

Kommentare


bottom of page