Constat
L'organe cense reparer automatiquement les gates annules est, en pratique, servi ~1 fois sur 5, et
quand il part il fait la queue derriere la congestion qu'il vient reparer. Une PR dont le gate a ete
annule attend donc ~2 h 30 sa reparation « automatique ».
Les trois faits sont mesures le 2026-09-12, et ils se composent.
1. Les tirs de cron sont jetes
.github/workflows/pr-gate-stale-sweep.yml declare :
on:
schedule:
- cron: '7 * * * *' # horaire
Tirs schedule reellement servis : 01:03:49Z → 05:43:36Z → 10:39:33Z. Ecarts de 280 et
296 minutes contre 60 declarees — environ un tir sur cinq. GitHub jette les declenchements
planifies sur un depot charge, silencieusement : rien dans l'UI ne distingue « pas de tir » de « rien
a faire ». C'est le mode de defaillance le plus couteux, parce qu'il est invisible.
2. Les 25 runners sont sur une seule machine
Tous les runners self-hosted du depot vivent sur myia-po-2024. Il n'y a pas de second hote.
| Pool |
Total |
Occupes (a l'instant de la mesure) |
coursia-linux (+coursia-ephemeral) |
11 |
10 |
coursia-waiter |
12 |
6 |
coursia-lean (+coursia-ephemeral) |
2 |
1 |
File au meme instant : 80 queued / 18 in_progress (en repli depuis 167/29 une heure plus tot).
Les slots coursia-waiter sont tenus par des agregateurs PR gate qui attendent jusqu'a 45 min
(--timeout-min 45) des constituants coinces dans cette file. Au plafond, le job est annule — et un
timeout-minutes rend cancelled, jamais failure, d'ou l'invisibilite traitee en #15769.
3. Le reparateur est route sur le pool le plus contendu
pr-gate-stale-sweep.yml:138
runs-on: [self-hosted, coursia-ephemeral, coursia-linux]
Dispatch manuel a 12:57:27Z (run 34695083294) pour reprendre les 7 gates annules : encore
queued 12 minutes plus tard, en attente du pool a 10/11 occupes — pendant que coursia-waiter
avait 6 slots libres.
Le job du sweep est un travail gh/API (il re-agrege des verdicts et relance des runs). Rien n'y exige
le pool de build. Le commentaire l.96-99 documente ce routage comme volontaire (acceptance #12728,
« queue collapses from ~6000-8000 s to near zero ») : cette acceptance a ete lue sur une file bien plus
courte qu'aujourd'hui, et elle ne tient plus.
Pistes, par ordre de cout croissant
- Re-router le sweep hors du pool de build. Attention : le router sur
coursia-waiter cree un
risque d'interblocage (les waiters sont tenus par les agregateurs que le sweep doit debloquer). Un
pool dedie de 1-2 slots, ou un runner hebergé GitHub pour ce job precis, evite le cycle — c'est un
job gh, il n'a besoin d'aucune ressource locale.
- Ne pas dependre du
schedule : ajouter un declencheur workflow_run sur la fin des gates, ou
accepter que le dispatch manuel coordinateur soit le chemin nominal et le dire dans le fichier.
- Repartir les runners sur un second hote. C'est le seul remede a la cause racine — mais il est
materiel, donc a arbitrer, pas a decider ici.
Ce que cette issue ne demande pas
Pas de ralentissement de la production des lanes. La R0 de coordinator-discipline.md est explicite :
une saturation de la digestion se repare ou se capacite, elle ne devient jamais une politique de
freinage des producteurs. Cette issue existe pour capaciter.
Acceptance
- Un gate annule par congestion est re-agrege en moins d'une heure, sans geste manuel.
- La mesure qui le prouve est l'ecart entre
created_at du run de sweep et started_at de son job —
la ligne de mesure existe deja dans le workflow (l.96-99).
- La cadence effective du
schedule est mesuree sur 24 h et comparee aux 24 tirs declares.
Constat
L'organe cense reparer automatiquement les gates annules est, en pratique, servi ~1 fois sur 5, et
quand il part il fait la queue derriere la congestion qu'il vient reparer. Une PR dont le gate a ete
annule attend donc ~2 h 30 sa reparation « automatique ».
Les trois faits sont mesures le 2026-09-12, et ils se composent.
1. Les tirs de cron sont jetes
.github/workflows/pr-gate-stale-sweep.ymldeclare :Tirs
schedulereellement servis :01:03:49Z→05:43:36Z→10:39:33Z. Ecarts de 280 et296 minutes contre 60 declarees — environ un tir sur cinq. GitHub jette les declenchements
planifies sur un depot charge, silencieusement : rien dans l'UI ne distingue « pas de tir » de « rien
a faire ». C'est le mode de defaillance le plus couteux, parce qu'il est invisible.
2. Les 25 runners sont sur une seule machine
Tous les runners self-hosted du depot vivent sur
myia-po-2024. Il n'y a pas de second hote.coursia-linux(+coursia-ephemeral)coursia-waitercoursia-lean(+coursia-ephemeral)File au meme instant : 80
queued/ 18in_progress(en repli depuis 167/29 une heure plus tot).Les slots
coursia-waitersont tenus par des agregateursPR gatequi attendent jusqu'a 45 min(
--timeout-min 45) des constituants coinces dans cette file. Au plafond, le job est annule — et untimeout-minutesrendcancelled, jamaisfailure, d'ou l'invisibilite traitee en #15769.3. Le reparateur est route sur le pool le plus contendu
pr-gate-stale-sweep.yml:138Dispatch manuel a
12:57:27Z(run34695083294) pour reprendre les 7 gates annules : encorequeued12 minutes plus tard, en attente du pool a 10/11 occupes — pendant quecoursia-waiteravait 6 slots libres.
Le job du sweep est un travail
gh/API (il re-agrege des verdicts et relance des runs). Rien n'y exigele pool de build. Le commentaire l.96-99 documente ce routage comme volontaire (acceptance #12728,
« queue collapses from ~6000-8000 s to near zero ») : cette acceptance a ete lue sur une file bien plus
courte qu'aujourd'hui, et elle ne tient plus.
Pistes, par ordre de cout croissant
coursia-waitercree unrisque d'interblocage (les waiters sont tenus par les agregateurs que le sweep doit debloquer). Un
pool dedie de 1-2 slots, ou un runner hebergé GitHub pour ce job precis, evite le cycle — c'est un
job
gh, il n'a besoin d'aucune ressource locale.schedule: ajouter un declencheurworkflow_runsur la fin des gates, ouaccepter que le dispatch manuel coordinateur soit le chemin nominal et le dire dans le fichier.
materiel, donc a arbitrer, pas a decider ici.
Ce que cette issue ne demande pas
Pas de ralentissement de la production des lanes. La R0 de
coordinator-discipline.mdest explicite :une saturation de la digestion se repare ou se capacite, elle ne devient jamais une politique de
freinage des producteurs. Cette issue existe pour capaciter.
Acceptance
created_atdu run de sweep etstarted_atde son job —la ligne de mesure existe deja dans le workflow (l.96-99).
scheduleest mesuree sur 24 h et comparee aux 24 tirs declares.