Passer de cron à launchd, épisode 2

On l'a vu dans l'épisode 1 de "Passer de cron à launchd", la syntaxe de launchd est vraiment très verbeuse par rapport à celle des crontabs. De plus, launchd pose rapidement des problèmes quand il s'agit de définir des périodicités un peu excentriques ou sophistiquées.
Par exemple, si dans cron je veux créer une tâche qui s'exécutera toutes les 30 minutes tous les jours, j'écris ceci :

*/30 * * * *      /ma/commande

Alors, crond va lancer /ma/commande à 0h00, 0h30, 1h00, ... 23h30 tous les jours.
Pour faire la même chose avec launchd J'ai a priori deux possibilités : StartInterval et StartCalendarInterval. StartInterval est simple et permet de régler en 2 lignes mon intervalle de temps :

<key>StartInterval</key>
<integer>1800</integer>

Seulement, il existe une limitation de taille. StartInterval ne sait pas qu'il doit commencer à 0 minute pour assurer le rythme "heure + 0 minute, heure + 30 minutes". Si le plist launchd est chargé à 7h42, heure du démarrage de la machine par exemple, et bien la première exécution va se produire immédiatement. La prochaine aura bien lieu 30 minutes après, et ainsi de suite. On aura donc les heures de lancement suitantes : 7h42, 8h12, 8h42, ...

Si vous avez besoin d'un lancement à heure fixe, il faut donc oublier complètement StartInterval et vous rabattre sur StartCalendarInterval. Ce dernier impose les dates et heures de lancement, mais il souffre de deux gros défauts.
Premier défaut, et non des moindres : jusqu'à Mac OS X 10.5 le comportement de StartCalendarInterval était bugué, ce qui le rendait pratiquement inutilisable. D'ailleurs, je n'ai pas de certitude absolue sur son bon fonctionnement dans Leopard. Le second défaut, c'est la verbosité de sa syntaxe. Reprenons l'exemple ci-dessus, et transposons-le à StartCalendarInterval. On obtient le code suivant, juste pour la gestion de la périodicité :

<key>StartCalendarInterval</key>
<array>
	<dict>
	    <key>Minute</key>
	    <integer>0</integer>
	</dict>
	<dict>
        <key>Minute</key>
        <integer>30</integer>
	</dict>
</array>

Maintenant, imaginez le nombre de lignes nécessaires pour imposer un lancement aux minutes 0, 10, 20, 30, 40, et 50 : 27 lignes sans compter la gestion de la commande, de l'utilisateur, du header xml..., là où une seule ligne de crontab suffit.

Passons aux choses sérieuses avec un exemple de la vraie vie. Je veux lancer un script de sauvegarde sur ma machine professionnelle, à 12h30 et à 18h30, du lundi au vendredi. Avec cron, c'est simplissime :

30 12,18 * * 1,2,3,4,5      /mon/script/de/sauvegarde

Maintenant, si on veut reproduire la même chose avec launchd, on obtient un fichier xml très long. Je peux placer dans le même bloc dict au maximum une fois chaque mot clé (ici Minute, Hour, Weekday). Heureusement, les astérisques dans la crontab ne sont pas reportées dans launchd car un mot clé absent dans le plist correspond à une astérisque dans la crontab. Je n'ai qu'une valeur pour le mot clé Minute, j'ai deux valeurs pour le mot clé Hour, et 5 pour Weekday. Donc je vais avoir 2 blocs dict pour chaque jour (un pour chaque heure), et chaque bloc va faire 8 lignes. J'ai 5 jours, et 2 blocs de 8 lignes pour chacun, donc j'obtiens 80 lignes de xml uniquement pour la définition de la périodicité ! Ci-dessous, les 16 premières lignes :

<dict>
	<key>Weekday</key>
	<integer>1</integer>
	<key>Hour</key>
	<integer>12</integer>
	<key>Minute</key>
	<integer>30</integer>
</dict>
<dict>
	<key>Weekday</key>
	<integer>1</integer>
	<key>Hour</key>
	<integer>18</integer>
	<key>Minute</key>
	<integer>30</integer>
</dict>

Merci Apple pour cette simplification.

Cet article a été publié dans Unix avec les mots-clefs : , . Bookmarker le permalien. Laisser un commentaire ou faire un trackback : URL de trackback.

9 commentaires

  1. lolopb
    Le 4 janvier 2008 à 11:38 CET | Permalien

    Même si je suis d'accord, c'est très bavard, ça vient surtout du XML en lui-même qui n'a jamais allégé le code à taper pour arriver à un résultat donné...

  2. Le 4 janvier 2008 à 11:43 CET | Permalien

    Apple aurait pu faire plus court. En se limitant à "integer" pour la valeur des clés, on obtient une situation délirante. Si on avait pu mettre comme dans cron plusieurs valeurs on aurait économisé énormément de place, tout en rendant plus facile la maintenance et l'édition des plists.
    En reprenant l'exemple final que je donne, si on pouvait mettre 12,18 dans Hour, et 1,2,3,4,5 dans Weekday, on passerait de 80 lignes à 8.

  3. lolopb
    Le 4 janvier 2008 à 19:36 CET | Permalien

    Oui, je suis d'accord mais ils ont une DTD ultra-basique pour les plist et n'ont certainement pas envie de refaire tout et donc de se taper un parseur supplémentaire. Je soupçonne le parsing des plist d'être fait par un moteur simpliste taillé sur mesure pour la DTD.

  4. Le 17 septembre 2008 à 16:50 CET | Permalien

    Super tutos sur launchd.

    Pour ceux qui veulent vraiment créer rapidement des fichiers sans trop se prendre la tête, je recommande VIVEMENT l'outil Lingon
    http://sourceforge.net/projects/lingon

  5. patpro
    Le 17 septembre 2008 à 16:58 CET | Permalien

    En fait, j'ai déjà parlé de Lingon dans un article plus ancien. À l'époque c'était une perle ! Depuis la 10.5, je crois, Lingon n'est plus que l'ombre de lui même. Il est devenu bien moins intéressant (et c'est dommage).

  6. Maelvon
    Le 26 août 2009 à 16:10 CET | Permalien

    Il faut mettre les <dict> des jours dans une <array> on dirait ?

  7. patpro
    Le 26 août 2009 à 16:23 CET | Permalien

    Oui, bien sûr, le dernier bout de code que je donne n'est qu'un extrait, il faut l'encapsuler dans

    <key>StartCalendarInterval</key>
    <array>
    ...
    </array>

    Lui même encapsulé dans une plist complète.

  8. Thierry
    Le 12 mai 2010 à 16:54 CET | Permalien

    Merci pour ces précieuses infos sur Launchd.
    Je préfère 1000 fois cron.
    Je ne sais pas si c'est moi, launchd ou mail, mais je suis en train de devenir fou avec un script d'envoi de mail d'erreur en cas de problème durant le déroulement d'une tache répétitive !!!

  9. Grégory Mongrand
    Le 17 août 2010 à 20:45 CET | Permalien

    OK c'est pas simple mais grâce à ces exemples et explications c'est nettement plus clair.
    MERCI

Laisser un commentaire

Votre e-mail ne sera jamais publié ni communiqué. Les champs obligatoires sont indiqués par *

*
*

Vous pouvez utiliser ces balises et attributs HTML : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>