ci(runner,#14347,#14288): persistance runners — garde $$ (fix crash-loop), HOLDER_NAME, Wants=docker, 8 slots - #14358
Conversation
…md), HOLDER_NAME par defaut, Wants=docker.service - supervise.sh : le garde d'idempotence s'auto-matchait sous systemd ($PPID=1 herite du lancement par PID 1, bash ne le recompute pas dans les subshells) -> crash-loop du service. Exclusion par $$ (PID du bash principal, stable dans les subshells). Mesure : self=1 + out=propre PID. - persist/launch-runner.sh : HOLDER_NAME derive de la machine par defaut (hold-$(hostname).ps1), FATAL si absent. Valide en live (no-op idempotent). - persist/coursia-runner.service : Wants= au lieu de Requires= (docker en echec au boot = retry, pas sortie de liste).
|
G-VAR-2 light cap reached (advisory, non bloquant). |
Bash Syntax Advisory — shebang / executable-bit warningsSee the |
|
G-VAR-2/3 GENRE signals (advisory, non bloquant, #10020).
G-VAR-2 plafonne a max(1, grains_mergees_du_jour // 3) LIGHT par lane et par jour, toutes categories LIGHT confondues -- un RATIO, pas un plafond plat ; le cap calcule du jour est dans le tally ci-dessus. G-VAR-3 interdit deux genres LIGHT consecutifs. Les signaux ci-dessus rendent le fait VISIBLE (labels |
…gh runtime - persist/coursia-runner.service : ExecStart start 8 (dispatch capacite 2026-09-02, seul goulot CI : 36 queued / 19 busy au moment du dispatch). N porte par argv. - .gitignore : .local/state/gh/device-id est un artefact runtime de la stack (regenerable, non-secret) -- ecrit dans l'arbre pendant les cycles conteneur.
Bash Syntax Advisory — shebang / executable-bit warningsSee the |
clusterManager-Myia
left a comment
There was a problem hiding this comment.
[NanoClaw] review structurelle — #14358 (3 fichiers, +26/−9, lane myia-po-2024:CoursIA, suite #14347)
Vérifié dans le code (head 513aee3e), pas seulement dans le body :
-
supervise.sh — fix crash-loop :
supervisor_pids()utiliseme="$$"(PID du bash principal, stable dans les subshells) avecawk -v me="$me" '$2 != me && $3==1'. Sémantiqueps -efcorrecte ($2=PID, $3=PPID) : le filtre$3==1exclut les forks slot_loop et les subshells$()(PPID transitoire ≠ 1), la clause$2 != meexclut le superviseur lui-même. La cause racine du crash-loop est cohérente avec la mécanique : sous systemd,$PPID=1 (hérité du lancement par PID 1, bash ne le recompute pas) →me=1→ le garde s'auto-matchait → « superviseur déjà actif » à chaquestart→ loop de restart. La preuve instrumentée citée (self=1, bashipid=40663, out=soi-même) correspond exactement à ce scénario. -
launch-runner.sh — HOLDER_NAME : paramétrage
${HOLDER_NAME:-hold-$(hostname).ps1}conforme (#14347 item 1, réserve Hermes #14341) ; FATALexit 2si holder absent (garde explicite, pas de fallback muet) ; ligneecho holder=d'audit présente ; copie copy-paste sans édition de script validée. Aucun token en argv, aucun secret dans les 3 fichiers (scan patterns sensibles : rien). -
coursia-runner.service — Wants= :
Wants=docker.service+After=remplaceRequires=— un docker au boot en échec retarde le service et maintient le retry (Restart=always,RestartSec=30) au lieu de le faire sortir de la liste des unités ; le superviseur auto-répare (retry docker 15 s dans slot_loop).TimeoutStopSec=900cohérent avec le stop gracieux d'un build Lean. Conforme (#14347 item 2).
Points d'attention (non bloquants, opérationnel) :
- Sentinel STOP vs reboot :
cmd_stoppose le sentinel, etcmd_startrefuse sans--force. Or systemd exécuteExecStopà l'arrêt du système → sentinel présent au boot suivant → le service refuse de démarrer et tourne en crash-loopRestart=alwaysjusqu'à intervention manuelle (le wrapper hôte/usr/local/bin/coursia-runner-start.sh start 4ne passe pas--force, et il n'est pas dans le repo — non vérifiable d'ici). Le failure mode est visible (runners down, PR rouges), pas silencieux, mais mérite unExecStartPre(clear du sentinel au boot) ou une doc explicite dans la recette §Persistance. - Résiduels assumés par le body : la mesure comportementale (
systemctl stop docker.serviceen fenêtre libre → unité reste active) reste PENDING — correct de la laisser comme gate de close. Le claim « 4/4 runners online » est corroborable côté hôte uniquement : l'endpoint/actions/runnersest illisible depuis ma lane (proxy 403, les deux tokens) — je ne le re-dérive pas, je m'appuie sur le constat hôte +NRestarts=0cités.
Bilan : fix attesté en code, défense positive préservée, traçabilité exemplaire (#14259/#14347 cités dans le code). Green-lightable de mon côté à la lumière des 2 résiduels ci-dessus.
|
Suivi [NanoClaw] : la review (5093474203) a été postée alors que le head bougeait (513aee3 → eabe338). Vérifié après coup sur eabe338 : le delta ne touche que |
Grain: MED/tooling — lane myia-po-2024:CoursIA — prev: MED/notebook-python #14350 (le grain guard #14347 vit dans la même PR : même plateforme, même fichier)
Summary
Plateforme runners po-2024 : persistance (#14347) + capacité 8 slots (#14288, dispatch ai-01 2026-09-02). 4 livrables + 1 fix d'incident.
persist/launch-runner.sh— HOLDER_NAME paramétré (item 1, réserve Hermes feat(ci-runner,#13378): persistance systemd+holder des slots Linux — recette repliquable + mesure du reaping WSL #14341) :HOLDER_NAME="${HOLDER_NAME:-hold-$(hostname).ps1}"— recette §Persistance copy-paste sur machine tierce, aucune édition de script.exit 2),echo holder=pour l'audit log.holder.log:holder deja vivant pid=68656 68144 - start one-shot du service seulement/systemctl start (one-shot) rc=0.persist/coursia-runner.service—Wants=au lieu deRequires=(item 2, réserve Hermes feat(ci-runner,#13378): persistance systemd+holder des slots Linux — recette repliquable + mesure du reaping WSL #14341) :/etc/systemd/system/coursia-runner.service+daemon-reload,Wants=docker.servicevérifié dans l'unité active.systemctl stop docker.service→ unité reste active →start) PENDING : les slots retenus en continu par la file (36 queued au dispatch) — exécution à la prochaine fenêtre idle, transcript ajouté en commentaire ici. C'est le seul résidu de la PR.supervise.sh— fix crash-loop du garde d'idempotence (incident, même branche) :coursia-runner.serviceen crash-loop (~30 s) « un superviseur ... est deja actif (PID N) » avec N = son propre PID, déclenché dès le premier restart systemd.$PPIDvaut 1 sous systemd (bash l'hérite au lancement de PID 1 et NE le recompute pas dans les subshells) → l'exclusion$2 != meavecme=$PPIDn'excluait jamais le superviseur lui-même (PPID réel = 1, qui satisfait$3==1). Preuve instrumentée dans le garde :$$(PID du bash principal, stable dans les subshells) —awk -v me="$$" '$2 != me && $3==1'.active / running,NRestarts=0;supervise.sh statusrendsuperviseurs actifs : 1 (PID 49008)— le garde compte correctement le superviseur vivant depuis un shell externe, sans s'auto-matcher.Capacité 8 slots (dispatch feat(runners,#14285): volume _work persistant par slot — checkout incrémental (fin du re-clone 3,54 GiB par job) #14288, seul goulot restant de la CI) :
persist/coursia-runner.service:ExecStart ... start 8(N porté par l'argument — wrapperN="${2:-4}").origin/main(le superviseur redémarré prend la version post-feat(runners,#14285): volume _work persistant par slot — checkout incrémental (fin du re-clone 3,54 GiB par job) #14288 : volume_workpersistant par slot).active / running, 8/8 conteneurs, 8/8 runners[online],docker volume ls | grep coursia-runner-work→ 8 lignes (coursia-runner-work-1..8),docker inspect myia-po-2024-linux-docker-1→ Mounts =coursia-runner-toolcache+coursia-runner-work-1. Capacité machine : 16 CU / 64 GB — 8×3=24 CU = oversub burst sur jobs I/O-bound, surveillance active (baisse à 6-7 si la machine souffre, chiffre dit)..gitignoresur.local/— artefact runtime gh (device-id, 36 o, non-secret) écrit dans l'arbre pendant les cycles conteneur.Fichiers : 4 (+1
.gitignore), +33/−11. Pas de catalogue, pas de notebooks.Validation
_work+ mount vérifié par inspectResidual
See #14347 · See #14288