refactor(runner): link runner bits instead of copying them - #5
Merged
Merged
Conversation
Preparing a runner duplicated the whole cached release into its workdir. On the KARE host that is 675MB per runner and 343 runners a day, so ~231GB written and deleted daily, which made ghr the single largest disk writer on the box while the runner bits are read-only for the job's lifetime. copyFile now hardlinks and falls back to the byte copy when the link is refused (cross-device, link limit), so behaviour is unchanged everywhere the link cannot be made. Directories and symlinks keep their existing handling.
RedBoardDev
force-pushed
the
perf/link-runner-bits
branch
from
August 14, 2026 17:43
28e2471 to
495983e
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Constat
Préparer un runner recopie l'intégralité de la release en cache dans son workdir. Mesuré sur l'hôte KARE :
pidstatsur cet hôte classe ghr premier écrivain disque de la machine, à 132 Mo/s en rafale, devant lesRunner.Workereux-mêmes. Pendant ces rafales la latence disque passe de 0,58 ms à 75,83 ms avec une file de 553 requêtes, ce qui fait déraper les stepsInitialize containersetStop containersdes jobs (20 s → 1m43, 7 s → 1m51 sur un run mesuré).Or ces fichiers sont en lecture seule pendant toute la vie du job : le runner écrit dans
_work,_diaget les fichiers de configuration qu'il crée lui-même, jamais dans ses propres binaires. Le runner est lancé en JIT éphémère (ACTIONS_RUNNER_INPUT_JITCONFIG), donc il ne se met pas à jour lui-même non plus.Changement
copyFiletenteos.Linket retombe sur la copie octet par octet si le lien est refusé (autre système de fichiers, limite de liens). Le comportement est donc inchangé partout où le lien est impossible. Les répertoires et les liens symboliques gardent leur traitement existant, y compris les gardes contre les symlinks absolus ou qui s'échappent.Tests
Deux tests ajoutés : l'un vérifie que les fichiers réguliers sont bien liés (
os.SameFile), l'autre que le repli en copie produit un fichier indépendant quandos.Linkéchoue. Les 362 tests du dépôt passent,gofmtetgo vetsont propres.Risque à connaître
Les fichiers du workdir partagent désormais leur inode avec le cache. Si un jour quelque chose écrit en place dans un fichier du runner, la modification atteindrait le cache partagé et casserait tous les runners provisionnés ensuite. Le commentaire dans le code nomme ce piège.