CI incontrôlée
Un agent de code qui pousse, relance ou ouvre des pull requests en boucle peut épuiser vos minutes de runner en quelques heures, sans que rien ne vous prévienne avant l’e-mail des 80 % d’utilisation. fremforge surveille ce cas.
Ce qui est mesuré
Toutes les 5 minutes, pour chaque organisation, fremforge examine les 60 dernières minutes d’exécutions Actions sur ses runners hébergés et mesure :
| Signal | Quoi | Seuil |
|---|---|---|
| Exécutions par personne | Exécutions lancées par une personne dans l’organisation | Plus de 3 fois l’heure normale la plus chargée de cette personne, et jamais moins de 80 |
| Minutes de runner par personne | Minutes de runner consommées par ces exécutions | Plus de 3 fois l’heure normale la plus chargée de cette personne, et jamais moins de 600 |
| Pushes vers une pull request | Commits distincts poussés par une personne vers une même pull request | Plus de 12 |
« L’heure normale la plus chargée de cette personne » est son heure au 99e centile sur les 14 derniers jours, recalculée une fois par jour. Une personne comptant moins de 20 heures d’activité sur cette période est comparée à l’heure normale la plus chargée de l’organisation. Ainsi, une équipe dont les agents font tourner la CI toute la journée est mesurée par rapport à sa propre normale, et non par rapport à celle d’une équipe calme.
Le seuil des pull requests compte les pushes, pas les exécutions : un push lance autant d’exécutions que le dépôt a de workflows concernés.
Le sujet est toujours une personne. Une exécution qu’un agent lance pour le compte de quelqu’un est l’exécution de cette personne (l’utilisateur déclencheur de l’exécution), et il n’existe pas de comptes d’agents. Les bots, comme Renovate, sont mesurés de la même façon et signalés comme bots. Les exécutions que fremforge lance lui-même, comme les rafraîchissements de fichiers de verrouillage, ne sont pas mesurées.
Calibrage
Les seuils ont été fixés à partir d’un mois de CI où la plupart des exécutions proviennent d’agents de code. Rejoué dans le détecteur, ce mois ne déclenche aucune alerte dès lors que chaque personne a 14 jours d’historique.
Ce qui se passe
Quand un chiffre dépasse son seuil, fremforge enregistre une CI incontrôlée, une seule fois :
- Un e-mail à chaque propriétaire de l’organisation, nommant la personne, le périmètre (l’organisation ou une pull request) et les chiffres.
- Un e-mail à la personne à qui appartiennent les exécutions, rédigé à son intention, pour qu’elle puisse arrêter sa session. Pas pour un bot, et un propriétaire à qui appartiennent les exécutions reçoit un seul e-mail, pas deux.
- Un événement
ci.runawaydans le flux d’événements, un par dépôt concerné, pour qu’une session d’agent qui lit le flux le voie aussi. - Un événement d’audit (
ci_runaway.detected). - Une ligne sur la page d’utilisation de la CI (voir Dans la console).
Tant que le chiffre reste au-dessus du seuil, l’alerte est rafraîchie, sans nouvel e-mail. Elle prend fin d’elle-même après 60 minutes repassées sous le seuil.
Rien n’est arrêté, sauf si votre organisation a activé la pause.
La pause (sur activation)
Lorsque la pause est activée, une CI incontrôlée empêche aussi les runners de fremforge de démarrer les nouvelles exécutions de cette personne (ou, pour une alerte portant sur une pull request, ses nouvelles exécutions sur cette pull request) jusqu’à ce qu’un administrateur les reprenne. La pause est désactivée par défaut.
Ce que la pause ne fait jamais :
- Elle n’annule jamais rien. Une exécution retenue attend dans la file, affichée comme en pause sur Explorer → Actions, et démarre quelques secondes après une reprise.
- Elle n’arrête jamais une exécution déjà démarrée. Une exécution dont un job tourne déjà se termine, y compris ses jobs suivants.
- Elle ne retient jamais personne d’autre. Seules les exécutions déclenchées par la personne mise en pause (sur la pull request mise en pause) attendent.
- Elle échoue en mode ouvert. Si fremforge ne peut pas lire l’état de la pause, les exécutions démarrent normalement.
Elle ne retient que les runners hébergés de fremforge. Un runner que votre organisation fait tourner elle-même peut toujours prendre le job.
Une CI incontrôlée en pause ne prend pas fin d’elle-même. Un propriétaire la reprend, ou désactive la pause, ce qui reprend toutes les alertes en pause à la fois. Après une reprise, la même personne n’est pas signalée à nouveau pendant 60 minutes.
Les workflows planifiés de Forgejo (l’utilisateur forgejo-actions) sont mesurés et font l’objet d’alertes, mais ne sont jamais mis en pause.
Dans la console
Les propriétaires de l’organisation trouvent les alertes sous Build et déploiement → Utilisation de la CI, section CI incontrôlée (https://frem.sh/<org>/_admin/ci-usage#runaways) : l’interrupteur de pause, puis chaque alerte avec sa personne, son périmètre, son heure la plus chargée, son statut et un bouton Reprendre (ou Ignorer). Un bandeau en haut de la page indique quand une alerte est en cours.
API
Le jeton doit avoir runners:read pour lister, et runners:write pour reprendre ou basculer la pause. Chaque modification est auditée au nom de la personne pour laquelle agit l’appelant.
# List (state=live for open and paused only)
curl https://frem.sh/_app/api/v1/orgs/<org>/ci-runaways \
-H "Authorization: Bearer $FREMFORGE_TOKEN"
# Turn the pause on (or off: off resumes every paused runaway)
curl -X PUT https://frem.sh/_app/api/v1/orgs/<org>/ci-runaways/settings \
-H "Authorization: Bearer $FREMFORGE_TOKEN" \
-H "Content-Type: application/json" \
-d '{"pause": true}'
# Resume one (or close an open one)
curl -X POST https://frem.sh/_app/api/v1/orgs/<org>/ci-runaways/<id>/resume \
-H "Authorization: Bearer $FREMFORGE_TOKEN"Une alerte dans la liste :
{
"id": "4f0c…",
"status": "paused",
"scope": "pr",
"person": "alice",
"person_kind": "person",
"repo": "api",
"pr_number": 42,
"signals": ["pr_pushes"],
"runs": 48,
"heads": 16,
"minutes": 0,
"detected_at": "2026-10-25T09:40:00.000Z",
"paused_at": "2026-10-25T09:40:00.000Z",
"resumed_at": null
}status vaut open (alerte envoyée), paused, ended ou resumed. Le serveur MCP les liste avec list_ci_runaways.
Arrêter la boucle elle-même
L’alerte vous indique quelle personne a un travail qui tourne en boucle ; la session est la sienne. Arrêtez la session de l’agent, ou révoquez le jeton qu’elle utilise. Avec des jetons agissant pour le compte d’une personne (on-behalf-of), révoquer le jeton délégué arrête cette session sans toucher aux autres travaux de la personne.