Duizend buildruns per maand, en geen enkele kost iets ⚙️
Eerst een correctie. De eerste versie van dit artikel beweerde dat onze GitHub-buildminuten op waren en dat dit ons dwong tot een Pro-account. Dat klopte niet, op een manier die één blik in de documentatie had opgehelderd: voor openbare repositories zijn GitHub-buildminuten gratis. Artifacts en caches ook. Onze repository is sinds eind mei openbaar, dus we hebben nooit een minuut betaald en dat zullen we ook nooit doen. In plaats van de tekst stilletjes te corrigeren, schrijven we hem liever opnieuw en vertellen we wat de metingen echt lieten zien. Dat blijkt veel interessanter dan de foute versie.
Eerst gokken, dan kijken. De aanleiding was een avond waarop een afgeronde pull request in de browser stond en geen enkele check afging. Geen groene vinkjes, alleen stilte. We grepen naar de voor de hand liggende verklaring, “quotum op”, en namen een Pro-account. Daarna draaide alles weer, wat de theorie leek te bevestigen. Dat deed het niet: de stilte had een andere oorzaak (een pull request die GitHub op dat moment niet netjes met de hoofdbranch kan samenvoegen, start geen checks). Inmiddels hebben we de factureringsgegevens van elke afzonderlijke run opgevraagd. Het antwoord, voor elke run en elk besturingssysteem: factureerbare tijd = 0 milliseconden. Een platform steunen met een abonnement is prima, maar als verklaring voor deze repository houdt het geen stand.
Wat wel waar is: de machinerie is gegroeid. Elke pull request zet een kleine fabriek in gang: de hele server wordt gebouwd en de testsuite draait, linter en codeanalyse kijken mee, CodeQL zoekt naar beveiligingslekken en er worden Docker-images gemaakt voor de spelserver, het portaal, de WorldHost en de AI-backend. Een release voegt Windows-, Linux- en macOS-builds van de client toe, plus de WebGL-versie voor het browserspel. Sinds eind mei komt dat neer op 1.723 buildruns, waarvan 1.092 alleen in juli, verspreid over 131 samengevoegde pull requests in vier weken. En ja, de recente piek heeft echt met de AI te maken 😉: het project wordt 100% met AI-hulp ontwikkeld en met het grotere abonnement gebeurt er gewoon meer tegelijk. Alleen is de munteenheid geen geld, maar wachttijd.
Waar de wachttijd heen gaat. Gemeten over acht dagen: de normale checkrun (CI) 379 minuten, de CodeQL-beveiligingsanalyse 230, de releasebuilds 126, de rest is kleingeld. Eén release kost ongeveer 110 minuten rekentijd, verdeeld over WebGL (31,6), de Docker-image (19,4), macOS (13,7), Linux (13,7), de grote testpoort (12,1), Windows (10,9) en verpakken (7,2). Dat is de tijd tussen “klaar” en “installeerbaar voor jullie”.
En nu het ding dat echt schaars is: de cache. Zodat een build niet elke keer helemaal opnieuw begint, slaat GitHub tussenresultaten op, en daarvoor krijg je 10 GB per repository, hoe openbaar je ook bent. De onze bevat nu 5,3 GB in 63 items. Het probleem is de verdeling: ruwweg twee derde bestaat uit Docker-tussenlagen die bij elke run opnieuw worden geüpload, en die verdringen precies wat het meest zou helpen. Dat is de echte bottleneck, en geen enkel abonnement ter wereld koopt je daaruit vrij.
De mooiste vondst was een echte bug. Bij het bouwen maakt Unity een enorme tussenmap (Library) waarvan hergebruik minuten scheelt. Meten liet zien: voor Windows, Linux en macOS werd die map nooit opgeslagen. De builds probeerden hem braaf te herstellen, maar niemand schreef hem ooit weg. En de Windows-build was de enige met een cachesleutel zonder platformmarkering. Het gevolg: hij downloadde 1,7 GB aan tussenstatus van WebGL, die Unity vervolgens braaf weggooide voordat alles opnieuw werd geïmporteerd. Het log toont het zwart op wit: 257 seconden assetimport in plaats van 85 in het warme geval. Dat is bijna negen minuten verspild per release, omdat er één woord ontbrak in een sleutel.
Wat er nog meer bovenkwam. Onze testsuite draait drie keer per uitgebrachte commit (in de pull request, na het samenvoegen en nog eens bij de release). CodeQL controleert drie talen bij elke pull request, hoewel het niet eens een verplichte check is. Een cache voor de .NET-pakketten ontbreekt helemaal. Er wordt een emulator voor vreemde processorarchitecturen ingericht, terwijl we maar voor één bouwen. En 7,4 GB aan oude buildartifacts blijft liggen op de standaardbewaartermijn van 90 dagen. Niets dramatisch, maar samen is het een flink stuk levenstijd.
De les is dezelfde als die onze server ons leerde. Toen maten we dat de helft van het bezette geheugen helemaal niet naar het spel ging, maar naar Docker en de monitoring. Deze keer was het nog pijnlijker: we gingen uit van een rekening die nooit bestond en betaalden voordat we keken. Meten, niet gokken: die zin geldt blijkbaar pas als je hem echt hebt geïnternaliseerd. Het opruimwerk is gepland maar nog niet gedaan. Als het draait, vertellen we wat het ons heeft opgeleverd. 🚀
Opmerkingen