top of page

Mille esecuzioni di build al mese, e nemmeno una costa qualcosa ⚙️

Immagine del redattore: Marcel Dütscher
Marcel Dütscher
26 lug
Tempo di lettura: 4 min

Prima una correzione. La prima versione di questo articolo sosteneva che i minuti di build di GitHub fossero esauriti e che questo ci avesse costretti a passare a un account Pro. Era sbagliato, e in un modo che bastava un'occhiata alla documentazione per chiarire: per i repository pubblici i minuti di build di GitHub sono gratuiti. Anche gli artefatti e le cache. Il nostro repository è pubblico da fine maggio, quindi non abbiamo mai pagato un solo minuto e non lo faremo mai. Invece di correggere il testo di nascosto, preferiamo riscriverlo e raccontarvi cosa hanno mostrato davvero le misurazioni. Risulta molto più interessante della versione sbagliata.


Prima si tira a indovinare, poi si guarda. Lo spunto è stata una sera in cui una pull request finita stava lì nel browser e non partiva nemmeno un controllo. Nessuna spunta verde, solo silenzio. Abbiamo scelto la spiegazione ovvia, «quota esaurita», e abbiamo preso un account Pro. Dopo, tutto ha ripreso a girare, il che sembrava confermare la teoria. Non era così: il silenzio aveva un'altra causa (una pull request che GitHub in quel momento non riesce a unire in modo pulito con il ramo principale non avvia nessun controllo). Da allora abbiamo interrogato i dati di fatturazione di ogni singola esecuzione. La risposta, per ogni esecuzione e per ogni sistema operativo: tempo fatturabile = 0 millisecondi. Sostenere una piattaforma con un abbonamento va benissimo, ma come spiegazione per questo repository non regge.


Ciò che è vero: la macchina è cresciuta. Ogni pull request fa partire una piccola fabbrica: tutto il server viene compilato e la sua suite di test eseguita, linter e analisi del codice lo esaminano, CodeQL va a caccia di falle di sicurezza e vengono prodotte le immagini Docker per il server di gioco, il portale, il WorldHost e il backend dell'IA. Una release aggiunge le build del client per Windows, Linux e macOS, più la versione WebGL per il gioco nel browser. Da fine maggio fanno 1.723 esecuzioni di build, 1.092 solo a luglio, su 131 pull request unite in quattro settimane. E sì, il recente aumento ha davvero a che fare con l'IA 😉: il progetto è sviluppato al 100% con l'assistenza dell'IA e con l'abbonamento più grande semplicemente succedono più cose in parallelo. Solo che la valuta non è il denaro, ma il tempo di attesa.


Dove va a finire il tempo di attesa. Misurato su otto giorni: l'esecuzione normale dei controlli (CI) 379 minuti, l'analisi di sicurezza CodeQL 230, le build di release 126, il resto sono spiccioli. Una singola release costa circa 110 minuti di calcolo, divisi tra WebGL (31,6), l'immagine Docker (19,4), macOS (13,7), Linux (13,7), il grande controllo dei test (12,1), Windows (10,9) e il confezionamento (7,2). È il tempo che passa tra «fatto» e «installabile da voi».


E ora la cosa che è davvero scarsa: la cache. Perché una build non parta ogni volta da zero, GitHub conserva i risultati intermedi, e per questo si hanno 10 GB per repository, per quanto pubblici si sia. La nostra ne contiene attualmente 5,3 GB in 63 voci. Il problema è la distribuzione: circa due terzi sono livelli intermedi di Docker, ricaricati a ogni esecuzione, e scacciano proprio ciò che aiuterebbe di più. Questo è il vero collo di bottiglia, e nessun abbonamento al mondo ti ci fa passare.


La scoperta più bella è stata un vero bug. Durante la build Unity crea una cartella intermedia enorme (Library) il cui riutilizzo fa risparmiare minuti. La misurazione ha rivelato che per Windows, Linux e macOS quella cartella non veniva mai salvata: le build provavano diligentemente a ripristinarla, ma nessuno l'aveva mai scritta. E la build per Windows era l'unica con una chiave di cache senza alcun indicatore di piattaforma. Il risultato: scaricava 1,7 GB di stato intermedio di WebGL, che Unity poi buttava via diligentemente prima di reimportare tutto. Il log lo mostra nero su bianco: 257 secondi di importazione delle risorse invece di 85 nel caso caldo. Sono quasi nove minuti sprecati per ogni release, perché mancava una parola in una chiave.


Cos'altro è saltato fuori. La nostra suite di test gira tre volte per ogni commit rilasciato (nella pull request, dopo l'unione e ancora alla release). CodeQL controlla tre linguaggi a ogni pull request, anche se non è nemmeno un controllo obbligatorio. Manca del tutto una cache per i pacchetti .NET. Viene configurato un emulatore per architetture di processore estranee, anche se compiliamo solo per una. E 7,4 GB di vecchi artefatti di build restano lì con la conservazione predefinita di 90 giorni. Niente di drammatico, ma tutto insieme è un bel pezzo di vita.


La lezione è la stessa che ci aveva insegnato il nostro server. Allora avevamo misurato che metà della memoria occupata non andava affatto al gioco, ma a Docker e al monitoraggio. Stavolta è stata ancora più imbarazzante: abbiamo dato per scontato un conto che non è mai esistito e abbiamo pagato prima di guardare. Misurare, non indovinare: a quanto pare questa frase vale finché non la si è davvero interiorizzata. Il lavoro di pulizia è pianificato ma non ancora fatto; quando partirà, vi diremo cosa ci ha fruttato. 🚀

Post recenti

Mostra tutti

Commenti


Non puoi più commentare questo post. Contatta il proprietario del sito per avere più informazioni.
bottom of page