Instruction — le lanceur supervise plusieurs services
Date : 2026-08-13. Statut : décisions prises (BDFL, 2026-08-13), promues en ADR-157. Ce document reste la trace du raisonnement et des options pesées.
Pourquoi maintenant
Deux raisons, et la seconde est celle qui presse.
air-launchd supervise un seul service par invocation : parse_arguments rend un
ServiceSpec. C’est le dernier reste nommé du temps 3 de sa spec — « dépendances,
ordre, redémarrage » — et rien ne le décide encore : aucun ADR ne le prévoit.
Et il bloque l’étape 2b-ii de la campagne des managers : héberger le registre AirCom dans un lanceur mono-service donnerait un registre à client unique, dont la propriété essentielle — mettre deux services en relation — ne serait jamais exerçable.
L’observation qui découpe le chantier
2b-ii n’a pas besoin des dépendances. Il lui faut plusieurs services dans un même processus lanceur, rien de plus : deux services vivants, chacun avec son pid et son octroi, suffisent à ce qu’un registre ait un sens.
Le chantier se coupe donc en deux, et la coupe n’est pas de commodité — les deux moitiés répondent à des questions différentes :
| Ce que c’est | Décisions requises | |
|---|---|---|
| 3a — plusieurs services | N services supervisés en parallèle, sans relation entre eux | une : d’où vient la liste |
| 3b — dépendances et ordre | qui démarre avant qui, ce que « prêt » veut dire, l’arrêt en ordre inverse | plusieurs, et structurantes |
3a débloque 2b-ii. 3b peut attendre son propre ADR.
Question 1 — d’où le lanceur tient-il sa liste de services ?
TRANCHÉE : (a) — il balaie la racine des bundles de service.
- (a) Il balaie la racine des bundles de service —
/var/lib/air/services/<bundleId>/, disposition déjà tranchée par ADR-010. Installer un service, c’est y déposer son bundle et émettre son octroi ; le lanceur supervise ce qui est installé. Recommandé : aucune nouvelle notion, aucun nouveau fichier, et cela rejoint le provisionnement (ADR-121). - (b) Un artefact de configuration binaire énumérant les services. Conforme au Principe 11, mais crée une seconde source de vérité : un service installé mais absent de la liste, ou l’inverse, et il faut décider lequel gagne.
- (c) La ligne de commande, répétée. Ne préjuge de rien, mais ne monte pas : un système
ne se décrit pas en
argv.
Conséquence de (a), à assumer : le lanceur ne supervise plus ce qu’on lui dit, mais ce qu’il trouve. Un bundle mal installé devient un service qui démarre. C’est acceptable précisément parce que l’octroi arbitre : un bundle sans octroi valide ne se lance pas.
Question 2 — où vit la métadonnée de démarrage ? (apparue en instruisant la 1)
Le schéma du manifeste porte une liste d’exécutables — « vide ⇒ rien à lancer » — sans dire lequel démarre, et la politique de redémarrage n’a aucun foyer. Un bundle balayé doit pourtant dire comment il démarre.
TRANCHÉE : un bloc service dans le manifeste — point d’entrée (chemin relatif, parmi
les executables déjà empreintés), arguments, politique de redémarrage.
Écartés : un exécutable unique imposé (interdirait les binaires auxiliaires, que la plupart des services réels ont) et une configuration d’administration séparée (recréerait la seconde source de vérité qu’on venait d’écarter pour la liste des services).
Questions de 3b — pour mémoire, à ne pas trancher ici
- Où vivent les dépendances ? Dans le manifeste (signé par le développeur) ou dans l’octroi (signé par la machine) ? Un développeur qui déclare « tout dépend de moi » gagne un pouvoir sur l’ordonnancement de la machine — mais l’ordre de démarrage n’est pas un privilège, et le mettre dans l’octroi forcerait l’administrateur à le décider.
- Que veut dire « prêt » ? Le vocabulaire existe déjà —
EXPECT_READYet l’enregistrementReady— mais il reste à dire si une dépendance est satisfaite au lancement ou au prêt. - Que fait-on d’un service dont une dépendance meurt ? L’arrêter, le laisser vivre, le relancer quand elle revient ? C’est la question qui décide de la complexité de tout le reste.
- L’arrêt se fait-il en ordre inverse ? Et que faire d’un service qui refuse de s’arrêter alors que d’autres l’attendent ?
Ce que 3a implique techniquement
Aucune décision, mais du travail réel :
- la boucle de supervision passe d’un processus à N : un
ppollsur N canaux de lancement, N pidfds, plus l’arrêt — l’ensemble reste borné, donc sur la pile ; - les écoutes sont déjà tenues par le lanceur (temps 3c) : elles se répartissent par service ;
- la politique de redémarrage est par service et existe déjà (
RestartPolicy) ; - l’arrêt du lanceur doit arrêter tous ses services, et rendre un verdict d’ensemble.
Ce que 3a débloque immédiatement
2b-ii : le lanceur tient un AirRegistry, crée une paire de sockets par service, en
remet un bout par le genre 6 du canal (déjà livré, #715), sert Register/Lookup dans
sa boucle, et câble admit/forget (déjà livrés, #714) au cycle de vie. Le mur du
plafond aircom tombe alors.