Programmation avancée dans l'attente: sHellspawn – Démons dans Daemons

par David L. Fisher (Copyright © )

traduction par Soufiane Dardour (tous droits réservés) dardour.soufiane@gmail.com


Note: Les exemples de cet article utilisent l'implémentation originale de l'attente, dans le cadre du langage de script Tcl, mais les concepts s'appliquent à tout language qui prend en charge les mêmes principes de connexions de frai à systèmes distants ou des processus. Quelle que soit le language que vous choisissez, les mêmes enjeux et avantages s'appliquent. Je dois offrir une dernière mise en garde, que je ne peux souligner assez: toujours porter des lunettes de protection.

Comment faire face aux processus créés dans les eaux hostiles, et la gestion en constante évolution des ids spawn

Un des problèmes que les Expect programmeurs ont avec les spawn ids c'est l'attente pour essayer de les gérer lorsque les systèmes distants ont continuellement besoin d'un rétablissement de la connexion. Il existe de nombreuses façons efficaces de faire et beaucoup d'initiatives pour la paramétrisation du spawn id, mais j'ai trouvé qu'en ce qui concerne chaque processus engendré de la même manière que je considère fenêtre dans un système d'exploitation à fenêtres - Chacun est un interpréteur de commandes, et si j'ai besoin telnet ou ftp ou autre chose, je peux simplement taper cette commande dans le commande shell, peut-être m'assurer que je n'ai pas fait d'erreur, puis appuyez sur la touche retour.

Voici l'exemple du livre “Exploring Expect” écrit par Don Libes, et qu'on peut également trouver dans la page du manuel, en utilisant telnet en tant que session que nous créons. Nous avons tous suivi l'exemple simple et avons fait comme ça et ça marchait très bien (jusqu'à ce qu'il ne fonctionne pas):

catch {spawn telnet 1.2.3.4} pid; 

Techniquement, afin de détecter l'échec du processus de spawn, la commande ci-dessus devrait vraiment être implémentée de cette façon:

if { [catch {spawn telnet 1.2.3.4} pid] } { ## handle error, which is in the pid variable } 

En supposant le succès, nous avons maintenant une variable id spawn qui est notre poignée de la session telnet, et la commande spawn a retourné l'ID de processus de la nouvelle session dans la variable pid, pas l'ID du spawn. S'il ya une erreur dans le processus de spawn, la variable pid contient le message d'erreur. L'ID du processus peut être utile pour identifier le processus pour diverses raisons, mais c'est la variable spawn_id qui est nécessaire pour communiquer avec la session.

Il ya un problème inhérent et inévitable des processus de spawning directs en suivant l'exemple ci-dessus - si la commande spawn se bloque pour une raison quelconque, le script se bloque indéfiniment. De nombreux programmeurs se retrouvent à creuser profondément dans le code source de l'Expect pour trouver des façons de déterminer le moment où une telle anomalie se produit et comment le gérer, mais cela devrait être leur premier indice qu'ils cherchent au mauvais endroit pour trouver une solution. Parfois, les problèmes n'ont pas besoin des solutions, mais juste de simples contournements.

J'utilise telnet comme exemple, parce qu'il est largement utilisé dans les intranets d'entreprise et, comme d'autres protocoles de communication, il sont parfois fermés à distance, câbles de réseau physiques sont parfois accidentellement débranché ou souffrent d'une insuffisance électrique ou en échec, et le spawn id du processus associé devient invalide parce que le processus engendré a quitté. Tant que la capture d'exceptions lors de la communication avec ces sessions les empêche de se propager jusqu'à la pile des appels, et peut potentiellement causer la fin du script, il faut être prudent avec cette approche, en particulier lorsque la clause attendue continue à être exécutée jusqu'à ce que les critères définitifs soient réunis pour la clause afin de quitter et les commandes suivantes pour exécutés.

Les spawn ids ne sont jamais réutilisés lors de l'exécution d'un Expect programme - si vous frayer la même commande de nouveau, vous aurez un nouveau spawn id, mais avec un système 32-bit, vous ne serez pas à court de nouveaux spawn ids jusqu'à ce que vous ayez fait plus de quatre milliards de spawns, et si vous l'avez fait, vous n'êtes probablement pas entrain de faire les choses comme il faut (même en run-forever systèmes).

Beaucoup d'Expect développeurs utilisent le spawn id du spawn processus comme un indice ou une valeur dans un tableau, ou ont d'autres raisons de préfèrer faire référence à la session sur la base d'autres données, telles que l'adresse IP ou le nom d'hôte d'un système distant, le nom du programme spawn, etc. Le Spawn id sera toujours nécessaire poury envoyer des données, et pour écouter, une session particulière. Parfois, il semble plus facile de travailler avec des tables de recherche indirectes, mais ils ajoutent une couche de complexité inutile et à la gestion de ces sessions.

Étant donné le nombre de fois où j'ai eu à résoudre ce problème dans un code existant, et le nombre de fois où j'ai dû expliquer cette solution simple à des entrevues et à des cours que j'ai donnés dans l'automatisation, il semble utile de le partager avec l'ensemble de la communauté. Ma solution préférée est tellement simple qu'elle semble trop évidente, trop facile, et n'est donc pas quelque chose que les programmeurs moyens considéreraient comme la réponse qu'ils recherchent.

Encore une fois, je mentionne que la meilleure façon de considérer les sessions spawnés et la même que de considérer des fenêtres séparées dans un système de fenêtrage - chacun a une «identité» unique de l'utilisateur, et elle est intuitive lorsqu'on traite avec elles. De la même manière nous devons garder une trace des fenêtres représentées une session unique, les ids spawn devront être considérés comme les mêmes. Chaque fenêtre est un shell avec une ligne de commande, et tant que nous n'avons pas perdu la trace des sessions que nous avons en cours, nous savons instinctivement comment gérer chacune d'elles.

Voici comment non seulement maintenir le lien entre les processus et leurs ids spawn, mais aussi comment éviter une exception:

catch {spawn /your/favorite/shell} pid; exp_send "telnet 1.2.3.4\r"; 

Techniquement, pour détecter l'échec du processus à frayer ou de la la communication avec le processus après avoir réussi la frai, ces commandes doivent vraiment être mises en œuvre de cette façon:

if { [catch {spawn /your/favorite/shell} pid] } { ## gérer l'erreur, qui est dans la variable pid } elseif { [catch {exp_send "telnet 1.2.3.4\r"} err] } { ## gérer l'erreur, qui est dans la variable err } 

Certes, cela augmente l'utilisation des ressources deux fois plus que plusieurs processus démarrés (le shell hôte et la session telnet qui tournent dedans), mais les avantages l'emportent largement sur le prix. Plus particulièrement, a part en cas de défaillance catastrophique dans système local qui exécute le shell hôte (dans ce cas, vous avez probablement des problèmes beaucoup plus importants que d'être incapable de communiquer avec le système distant), vous avez encore un id spawn actif avec lequel communiquer. Même si le système distant est toujours connecté, le programme de communication (dans cet exemple, telnet) peut être interrompu par un signal suspendu, et le shell hôte est toujours disponible.

Le sous-produit avantageux de cette approche est que la frai d'un shell local ne doit jamais attendre, et un délai d'attente pour avoir une réponse de la commande subsequent exp_send peut facilement gérer les situations dans lesquelles un spawn directe peut suspendre le script entier.

De la même manière que vous feriez face à différents shells, des sessions de connexion, et d'autres fenêtres que vous utilisez, le système d'identification que chacun représente est important. Avec chacun, vous voulez une invite qui identifie de manière unique la session. Il est assez simple de définir une invite de commande qui identifie la session, et de l'inclure dans la clause attendue pour la détermination du processus qui a envoyé la sortie.

Une fois la commande invite appropriée est paramétrée, vous pouvez utiliser la variable de référence indirecte “any_spawn_id” par opposition à la référence de la variable directe “$any_spawn_id”dans votre expect_before et des déclarations expect_after pour détecter et identifier la sortie de chaque session. Il devient alors aisé de déterminer si vous avez perdu la connexion à un système distant sans pour autant perdre le spawn id associé, et vous pouvez interroger le shell hôte pour toute information qui vous plaît, au-delà des variables renvoyées par la commande exp_wait. Toutes les mêmes informations peuvent être trouvées dans le shell et dans les variables d'environnement, et le même spawn id peut être utilisé pour redémarrer la session.

La différence entre l'utilisation de la référence indirecte et directe pour“any_spawn_id” est que la référence directe est évaluée une fois, à l'entrée de la clause attendue. Cette liste est ensuite utilisé tout au long des itérations de la clause jusqu'à ce que les critères de sortie sont remplies, et au cours des itérations, une session a engendrée peut être perdu et les itérations suivantes peuvent causer une exception parce que le spawn id n'existe plus. La référence indirecte est évaluée à chaque itération, donc quand un spawn id est perdu (ou un nouveau est créé dans l'une des branches d'action), la liste sera mise à jour afin de refléter les nouveaux spawn ids actifs. (Une discussion plus approfondie qui aborde le contrôle actif de cette liste fera l'objet d'un prochain article).


David L. Fisher

Dave a travaillé en tant que développeur de logiciels depuis 1987, en commençant par des projets militaires puis des produits commerciaux. en 1995, il a commencé à faire du développement d'automatisation, et est maintenant un spécialiste de l'architecture et du développement des infrastructures d'automatisation, principalement pour Besoins de test de SQA, mais aussi pour les installations de logiciels / OS et l'exécution des systèmes pour toujours. Il est co-fondateur et directeur du développement de logiciels pour Cotse.Net, un web services d'abonnement à une base d'utilisateurs dans le monde entier. il a une vaste expérience avec Linux, FreeBSD, Cygwin, Tcl, Expect, Expressions régulières, et la théorie de l'automatisation et de la pratique. Pendant son temps libre, il étudie la neurolinguistique, l'astrophysique et acoustique, design des jeux stratégiques, joue du clavier et est publié compositeur / musicien. De plus, il adore les animaux et sauve ceux qui sont abandonnés ou maltraité il est webmaster de 3bunnies.org, le site d'un lapin sauveteur avec qui il travaille. Dave détient un baccalauréat de l'Université Tufts avec des crédits d'un master en génie informatique (génie électrique et informatique Science) avec une thèse sur la simulation acoustique tridimensionnel.


Adaptation française de la Gazette Linux

L'adaptation française de ce document a été réalisée dans le cadre du Projet de traduction de la Gazette Linux

Cet article est publié selon les termes de la Open Publication License. La Linux Gazette n'est ni produite, ni sponsorisée, ni avalisée par notre hébergeur principal, SSC, Inc.

Vous pourrez lire d'autres articles traduits et en apprendre plus sur ce projet en visitant notre site http://www.traduc.org/Gazette_Linux

Si vous souhaitez apporter votre contribution, n'hésitez pas à nous rejoindre, nous serons heureux de vous accueillir.