La gestion des jobs Powershell

Une fonction fondamentale de Powershell est la possibilité d’exécuter des commandes en parallèle à travers les jobs.

Lorsqu’on écrit des scripts, les commandes s’exécutent au fur et à mesure, de façon séquentielle. Mais il est parfois souhaitable d’exécuter les commandes en parallèle afin d’optimiser l’exécution dans son ensemble.

Par exemple si je devais auditer les ACL de tous les shares sur un serveur de fichier, je pourrais considérer  de créer un job pour chaque share et ainsi exécuter les audits en parallèle.

Ou si je devais convertir des fichiers d’un format vers un autre, la parallélisation devient intéressante, car je pourrais ainsi utiliser l’hyperthreading de mon CPU .

Par contre qui dit jobs en parallèle dit gestion des jobs, car si j’ai 10.000 shares à parser, je ne veux pas créer 10.000 jobs en parallèle, mais contrôler le nombre de jobs qui s’exécutent.

Imaginons une fonction appelée Convert-File qui prend en paramètres des variables propres à la conversion de fichiers.

Je peux l’appeler de façon séquentielle

Dans ce cas je dois attendre que file1 soit converti pour commencer la conversion de file2.

Je vais alors modifier ma fonction pour qu’elle crée des jobs Powershell.

J’utilise Start-Job en créant un scriptblock, ou bloc de code, à qui je passe les arguments en paramètre à travers -ArgumentList. Ceci est nécessaire car les variable $density, $quality, $source et $target sont des variables locales et elles appartiennent à la console Powershell actuelle, en créant un job, je crée une nouvelle console, et donc un nouveau contexte et donc mes variables locales ne seront pas visibles. Pour les référencer dans le script block on peut utiliser les éléments de $args, qui est l’array passée à travers  -ArgumentList. L’ordre sera le même que celui créé, donc attention à ça.

A chaque fois que j’appelle Convert-File un job est créé. Et ceci peut poser problème car aucune gestion des jobs en cours n’est faite. Du coup si j’appelle ma fonction énormément de fois, mon système risque d’avoir des problèmes. Nous avons besoin d’un peu de gestion.

Pour récupérer la liste des jobs démarrés, nous pouvons utiliser la cmdlet Get-Job. Nous pouvons envoyer le résultat de Get-Job vers Where-Object à travers un pipe pour vérifier la variable membre State, qui nous dit si le job est Running, ou Completed. Ceci nous donnera la liste des jobs en cours d’exécution.

$running est un array qui possède un compteur que nous pouvons vérifier pour savoir combien de jobs sont en cours d’exécution.

Avec cette information nous pouvons limiter le nombre de jobs. Car nous pouvons attendre qu’un de ces jobs soit fini pour démarrer le suivant.

On fera ceci avec Wait-Job en utilisant le paramètre -Any, ce qui veut dire que dés que un des jobs actuellement en cours est terminé, Wait-Job redonne la main.

Donc si on crée une boucle, on vérifie que le nombre de jobs en cours n’est pas supérieur à une variable qui définit le nombre de jobs maxi et attend qu’un de ces jobs soit terminé avant de démarrer le suivant.

Voici une vue globale de la fonction qui gère les jobs:

Quand j’utilise des jobs, je termine toujours le script par

Ceci permet de s’assurer que tous les jobs sont bien finis avant de continuer ainsi que de récupérer les outputs de toutes les consoles et ainsi savoir si tout s’est bien passé.

Partager ce contenu