Maîtriser la veille d’un Mac cloud pour fiabiliser la CI

Maîtriser la veille d’un Mac cloud pour fiabiliser la CI

Un archivage nocturne s’interrompt à mi-parcours et, le lendemain, il ne reste qu’une trace d’expiration du délai. Dès que la connexion au bureau distant est rétablie, la machine fonctionne pourtant normalement. Ce type d’incident ne doit pas être attribué d’emblée au réseau. Pour une CI sans surveillance sur un Mac cloud, il faut d’abord distinguer quatre états : la veille du système, la veille de l’écran, la fermeture de la session distante et l’arrêt du processus Runner. Ils peuvent produire des symptômes similaires, mais ne se corrigent pas au même niveau.

Commencer par identifier la couche où survient l’interruption

Avant de modifier la configuration, relevez les dernières lignes de sortie de la tâche en échec, son code de sortie et l’heure de démarrage de l’hôte. Si le journal s’arrête brutalement au milieu d’une commande de build sans changement de l’heure de démarrage du système, poursuivez l’analyse du côté de la veille et du cycle de vie des processus. Si l’heure de démarrage a changé, recherchez la cause du redémarrage au lieu de la masquer avec des paramètres empêchant la veille.

Symptôme Vérification prioritaire Conclusion fréquente
L’écran s’éteint, mais SSH et le build continuent displaysleep Seul l’affichage est en veille
SSH et la tâche deviennent inaccessibles en même temps sleep, journaux d’alimentation Le système est peut-être passé en veille
La tâche s’arrête à la fermeture du terminal Mode de lancement du Runner Le processus dépend de la session interactive
L’heure de démarrage de l’hôte a changé Historique des redémarrages, journal de la tâche Le système a redémarré

Commencez par collecter un état de référence sans modifier le système :

mkdir -p "$HOME/ci-audit"
date > "$HOME/ci-audit/power-baseline.txt"
pmset -g custom >> "$HOME/ci-audit/power-baseline.txt"
pmset -g assertions >> "$HOME/ci-audit/power-baseline.txt"
pmset -g sched >> "$HOME/ci-audit/power-baseline.txt"
sysctl -n kern.boottime >> "$HOME/ci-audit/power-baseline.txt"

pmset -g custom affiche les réglages propres aux différents modes d’alimentation, pmset -g assertions indique les processus qui empêchent actuellement la mise en veille et pmset -g sched permet de repérer les événements déjà planifiés. Ne tirez pas de conclusion à partir de la seule ligne sleep 0 : le profil de configuration et les assertions réellement actives doivent être examinés ensemble.

Distinguer la veille de l’écran de celle du système

Le Mac mini n’ayant pas de batterie, il faut surtout examiner la configuration sur secteur. La mise en veille de l’écran n’interrompt pas la compilation, et il est inutile de maintenir en permanence une sortie d’affichage virtuelle allumée pour la CI. Ce qui compte réellement pour les tâches sans surveillance, c’est la veille du système et la présence durable d’un processus Runner valide.

Sur un nœud dédié exclusivement aux builds continus, vous pouvez désactiver la veille du système sur secteur après avoir enregistré la configuration d’origine :

sudo pmset -c sleep 0 disksleep 0 powernap 0
pmset -g custom

Le paramètre displaysleep n’est pas modifié ici, car l’extinction de l’écran n’a aucune incidence sur un build en arrière-plan. Après l’exécution, relisez la configuration au lieu de considérer le succès de la commande comme une validation suffisante. Si la machine sert aussi aux sessions de bureau interactives, évaluez d’abord les plages d’utilisation de l’équipe. Pour une CI peu fréquente, mieux vaut empêcher la veille uniquement pendant chaque tâche plutôt que de modifier durablement la politique du système.

Les réglages d’alimentation permettent à la machine de rester active, mais ils ne transforment pas automatiquement un processus temporaire lié au terminal en service d’arrière-plan.

Encadrer chaque build avec caffeinate

caffeinate crée des assertions d’alimentation tant que son processus enfant reste actif. Son périmètre d’action est plus clair qu’une désactivation globale de la veille, ce qui le rend particulièrement adapté aux archivages planifiés, aux tests de longue durée et aux builds ponctuels de dépendances.

Créez un script d’encapsulation commun :

sudo install -d -m 0755 /usr/local/bin
cat <<'EOF' | sudo tee /usr/local/bin/ci-awake >/dev/null
#!/bin/zsh
set -euo pipefail
if (( $# == 0 )); then
  exit 64
fi
exec /usr/bin/caffeinate -ims "$@"
EOF
sudo chmod 0755 /usr/local/bin/ci-awake

Dans le Runner, n’ajoutez pas d’opérateur supplémentaire d’exécution en arrière-plan. Laissez le script d’encapsulation prendre directement en charge la commande cible :

/usr/local/bin/ci-awake /usr/bin/xcodebuild \
  -workspace App.xcworkspace \
  -scheme App \
  -configuration Release \
  -destination 'generic/platform=iOS' \
  build

L’option -i empêche la mise en veille du système pour cause d’inactivité, -m empêche la mise en veille du disque et -s empêche la mise en veille du système lorsque la machine est alimentée sur secteur. Une fois la commande cible terminée, l’assertion est libérée avec le processus d’encapsulation. Pendant le build, exécutez pmset -g assertions pour vérifier que l’assertion correspondante apparaît bien dans la sortie.

Détacher le Runner de la session distante

Si le build s’arrête encore après la fermeture de la session SSH ou graphique, le point à examiner n’est plus pmset, mais le processus parent du Runner. Un processus lancé manuellement depuis un terminal peut recevoir un signal de fin de session. Il peut également échouer si son répertoire de travail, ses variables d’environnement ou le contexte temporaire du trousseau disparaissent.

Un Runner destiné à fonctionner en continu doit être géré par launchd. Vérifiez au minimum les points suivants :

  1. Le service utilise un libellé fixe, par exemple local.ci.runner, et n’est pas relancé à chaque nouvelle connexion.
  2. Le répertoire de travail est défini par un chemin absolu et ne dépend pas du répertoire courant du terminal au démarrage.
  3. Le PATH, la sélection de la chaîne d’outils et le répertoire de cache sont configurés explicitement, sans hériter de la configuration du shell interactif.
  4. La sortie standard et la sortie d’erreur sont écrites dans des fichiers journaux distincts, avec une stratégie de rotation maîtrisée.
  5. Lorsqu’il reçoit un signal d’arrêt, le Runner sait terminer le processus enfant en cours afin de ne pas laisser de processus orphelin verrouiller le répertoire de build.

Pour vérifier un service utilisateur :

launchctl print "gui/$(id -u)/local.ci.runner"
pgrep -afil 'runner|xcodebuild'

Si le service doit fonctionner sans qu’un utilisateur soit connecté, utilisez un LaunchDaemon système et contrôlez-le avec launchctl print system/local.ci.runner. Ne conservez pas simultanément une instance utilisateur et une instance système, au risque de voir deux Runner se disputer le même répertoire de travail.

Valider la mise en production avec des preuves

Une fois la configuration terminée, planifiez une tâche de test dont la durée dépasse le délai au bout duquel les interruptions se produisaient auparavant. Pendant le test, fermez volontairement le bureau distant et le client SSH, sans arrêter le Runner. Après reconnexion, vérifiez le code de sortie de la tâche, l’horodatage des artefacts, le processus du service et les assertions d’alimentation.

Si une nouvelle interruption survient, collectez immédiatement les informations suivantes :

date
pmset -g assertions
pmset -g log | tail -n 120
sysctl -n kern.boottime
last reboot | head

La validation finale doit satisfaire quatre conditions : la veille de l’écran n’affecte pas la tâche ; le Runner reste actif après la fermeture de la session distante ; l’assertion de caffeinate est visible pendant le build ; cette assertion est automatiquement libérée à la fin de la tâche. Si l’un de ces critères échoue, revenez à la couche correspondante au lieu d’empiler de nouveaux paramètres d’alimentation.

Pour un Mac cloud dédié sur XcodeVM, la fiabilité d’une CI sans surveillance repose sur deux responsabilités bien séparées : la politique d’alimentation du système maintient le nœud en fonctionnement, tandis que launchd et l’encapsulation des tâches empêchent le processus de build de dépendre d’une session humaine. En configurant et en documentant séparément ces deux niveaux, la prochaine interruption laissera une cause identifiable plutôt qu’une simple trace de délai expiré.

Questions fréquentes

Désactiver la veille de l’écran empêche-t-il la veille du système ?

Non. displaysleep ne concerne que l’affichage. Il faut contrôler séparément la valeur sleep et les assertions d’énergie actives avec pmset.

Faut-il désactiver la veille de façon permanente ?

Cela convient à un nœud physique réservé à la CI continue après sauvegarde de sa configuration initiale. Pour des builds ponctuels, caffeinate limite la protection à la durée de la commande.

Pourquoi le build s’arrête-t-il quand la session distante est fermée ?

Le Runner est probablement attaché à un terminal interactif. Il doit être lancé comme service launchd autonome, puis son code de sortie et les journaux d’énergie doivent être examinés.

XcodeVM Mac dans le cloud

Choisissez une machine physique dédiée adaptée à votre charge de travail

Vérifiez la mémoire, le stockage, le nœud et la période de facturation avant de passer à la configuration de la commande. Tous les nœuds fonctionnent normalement 365 jours par an ; la disponibilité réelle est celle renvoyée en temps réel par la console.

Choisir une offre et la louer