Contexte et problème
Dans un monorepo Go comportant plusieurs jobs parallèles (lint, tests, builds), l'équipe CloudX a mesuré que les étapes actions/setup-go ralentissaient l’ensemble du pipeline. Le cache partagé par défaut utilise la clé setup-go-${os}-${arch}-go-${goVersion}-${hashFiles('**/go.mod')}. Cette clé ne varie que lorsqu’un changement touche l’OS, l’architecture, la version de Go ou le fichier go.mod. Or, lors de développements actifs, ces éléments restent stables, ce qui conduit à la restauration d’un état de cache initial pendant la plupart des runs. Les auteurs estiment que 86 % du travail effectué par l’action est inutile dans ce contexte.
Par ailleurs, plusieurs jobs parallèles résolvent la même clé et écrasent simultanément le cache sur le service GitHub. Le job qui termine en premier persiste un état partiel (par exemple, uniquement le cache de lint), ce qui force les jobs suivants à réexécuter des étapes déjà réalisées. Cette compétition entraîne une dégradation progressive du temps d’exécution jusqu’à ce que le go.mod soit modifié.
Mécanisme du cache Go et limites de actions/setup-go
Le toolchain Go sépare trois répertoires de cache : GOMODCACHE pour les modules, GOCACHE pour la compilation et GOCACHE également pour les tests. Chaque sous‑processus calcule un hachage complet de ses entrées et crée des fichiers index (-a) et données (-d) dans ~/.cache/go-build. Par exemple :
~/.cache/go-build
├── 00
│ ├── 000131ed61b57fbbb4ad26f5862b2aae4b648b33be167a7212fc680e7af79a93-a
│ ├── 000147cede28c3ff98a24adc10ac43dfbe11d00b4707945236c461031c0a4a5c-a
│ ├── 000427faba12a1cf22e9396ebc98ada8dbf714d648c1746176d26779c47bf05a-d
│ └── 0008027ee2ff469b29ad5f95fca2a6d74fba5caa5371dd80e2f5f3ba7f117bc8-d
Lorsque actions/setup-go restaure un cache unique, il ne distingue pas les sous‑caches de lint, de build ou de test. Ainsi, le cache de test peut être écrasé par le cache de build, même si les entrées de test n’ont pas changé. Le résultat est une réexécution systématique des tests, ce qui augmente le temps global de CI.
Solution cloudx-io/setup-go et résultats
CloudX a publié cloudx-io/setup-go, une implémentation « drop‑in » qui désactive la restauration du cache partagé et laisse chaque job gérer son propre répertoire GOCACHE. En conservant les caches locaux sur le runner, les jobs parallèles n’interfèrent plus. L’analyse de la même monorepo montre une réduction du temps d’exécution des jobs de test de 69 %. Cette amélioration correspond à la suppression de la majorité du travail redondant identifié précédemment (86 %).
Le projet est open‑source et inclut une documentation détaillée de la méthodologie de mesure CI utilisée par CloudX. Les équipes qui gèrent des projets Go de complexité moyenne peuvent reproduire ces gains en remplaçant simplement la ligne uses: actions/setup-go@v7 par uses: cloudx-io/setup-go@v1 dans leurs workflows.
Implications et bonnes pratiques
Le cas étudié souligne l’importance de vérifier la granularité des clés de cache dans les pipelines CI. Une clé trop générique entraîne la persistance d’états obsolètes et la contention entre jobs parallèles. En outre, la séparation explicite des caches de module, de compilation et de test permet d’exploiter pleinement la mémoïsation native de Go. Les équipes devraient envisager de désactiver le cache partagé lorsqu’elles utilisent plusieurs jobs parallèles ou, à défaut, de créer des clés incluant des hachages de fichiers de test ou de configuration afin de garantir l’unicité des artefacts restaurés.