passionrando a écrit :Les gars...
Vous qui êtes apparement des experts puisque Python c'est de la m.... Les scripts lancés au boot via rc.local sont de la fainéantise et je vais m'arrêter là....
Tu ne devrais pas être susceptible comme ça. Tous les gens qui viennent répondre à ta demande le font avec leurs compétences (quelle qu’elles soient) mais généralement le font de bon cœur (ou parfois juste pour se faire mousser en écrivant n’importe quoi sur des sujets non maitrisés mais les cas sont rares et connus). En ce qui me concerne, quand je parle de fainéantise d’un rc.local ou d’un cron pour se substituer à la bonne méthode de démarrage d’un service, c’est tout simplement parce que je le fais aussi quand je fais de l’expérimental et que j’ai la flemme de m’infuser un fichier de service init.d et aussi la flemme de coder la gestion des différents signaux indispensables aux bonnes pratiques qui vont avec. Dis-toi bien que comme beaucoup je suis ici totalement anonyme, que je ne te connais pas et par conséquent, je ne vois pas ce que j’aurais à gagner à te traiter de fainéant ou d’incompétent. Par contre, si ce que j’écris peut t’aider à avancer ou à comprendre quelque chose, j’aurais au moins la satisfaction de ne pas avoir perdu mon temps.
Trêve de courbettes et d’excuses, revenons-en aux signaux pour en finir une bonne fois pour toute avec ça (ce qui ne t’exemptera pas de te documenter dessus pour mieux les comprendre et les maitriser). Pas de baratin incompréhensible pour le débutant que tu es (ce n’est pas une insulte) mais juste de l’exemple à la fois simple, concret et explicite qui je l’espère te servira. Tu noteras que même si j'ai ce langage en horreur (comparé à d'autre), je n'hésite a me faire violence en l'utilisant pour essayer de rendre service
Voilà un premier petit code python tout bête que tu devrais comprendre facilement. Il ne fait que lancer une boucle infernale (j’insiste sur le infernale). On a ouvert un fichier txt et à chaque tour de la boucle, on incrémente la variable i et on l’écrit dans notre fichier. Un cas d’école en quelque sorte.
- sig_sample1.png (24.79 Kio) Vu 5980 fois
La procédure de test est simple, il suffit de lancer le programme, de le laisser tourner 20 ou 30 secondes et de stopper le processus en envoyant un simple
kill n°Pid depuis un autre terminal (ici pas besoin de chercher le n° de pid, il s’affiche au lancement du programme). Dans la fenêtre de terminal qui faisait tourner le programme, tu vas voir qu’il a bien reçu le signal et qu’il s’est bien arrêté comme prévu. Maintenant allons voir le contenu du fichier text.txt … Dans 99.9% des cas il sera vide ou incomplet
.
Second test. Cette fois ci on reprend le même programme mais on va ajouter un peu de code juste pour utiliser le signal afin de sortir proprement de cette boucle infernale.
- sig_sample2.png (45.04 Kio) Vu 5980 fois
Lancons le nouveau test jusqu’à compter toujours jusqu’à 20 ou 30 et renvoyons un même
kill n°Pid (attention, le pid a forcément changé). Cette fois ci aussi, le programme s’est arrêté toujours comme prévu. Allons maintenant voir ce que contient notre fichier text.txt et … hoooo miracle, il contient l’intégralité des données
.
Explication : Comme tous les langages et tous les systèmes, python a ses petites manies. Un truc de bien, c’est qu’il ferme automatiquement les fichiers ouvert quand il s’arrête. Par contre, il ne pousse les données qui sont encore dans le buffer d’écriture que si le fichier est fermé proprement par une instruction fichier.close(). Des cas d’anomalies comme ça (qui en fait n’en sont pas), je pourrais t’en citer des dizaines dans une dizaine de langages différents. Ici, rien de bien grave, on ne perd que des données, mais dans d’autre cas, cela peut être des sockets ou des fichiers qui deviennent inaccessible parce que pas fermés correctement, des connections à des bases de données qui persistent, du hardware qui reste occupé ect ect ect …
Dans le premier exemple, le kill arrête le programme forcement l’intérieur de la boucle, donc l’instruction f.close() n’est jamais atteinte. D’ailleurs comment le serait-elle puisque aucune interruption ou instruction ne permet de sortir de la boucle (ce que je traduis par infernale).Dans le second exemple, c’est différent. On a conditionné la boucle sur l’état de la variable wk et on modifie cette var quand on reçoit une demande d’arrêt SIGTERM (ou kill ou kill -15, tout ça c’est pareil). Une fois cette var passée à False, on sort normalement de la boucle et le programme peut poursuivre. En l’occurrence il ferme correctement le fichier par l’instruction f.close() puis retourne à la proc main pour se terminer normalement.
Donc non, un signal n’est pas une façon sale de sortir d’un programme. Ici on a utilisé le même signal et pourtant il y a une sortie douteuse et une sortie correcte. En fait, si le programme n’est pas conçu pour se terminer normalement quand il reçoit un signal d’arrêt alors il aura beaucoup de chance de s’arrêter ‘salement’. C’est toute la différence entre une programme qui s’arrête et un programme qui se termine (et la nuance n’est pas un détail).
Voila, je ne sais pas te dire quoi de plus. J’ai essayé d’être simple dans le code et en évitant les termes trop technique qui finalement font plus de mousse que de flamme. Quoi qu’il en soit, te voilà avec une méthode toute simple qui va te permettre de sortir proprement de tes boucles infernale et laisser tes programmes se terminer tout aussi 'proprement'. Ici l’exemple utilisait un simple kill (equivalent SIGTERM) , mais si tu veux que cette sortie soit tout aussi élégante en faisant un ctrl+c (équivalent SIGINT ou kill -2), il te suffit de rajouter la ligne suivante :
signal.signal(signal.SIGINT,sig_exit).
PS : une info au cas où tu ne l’aurais pas saisie ou mal compris. Tu n’es pas obligé d’envoyer ta commande kill depuis le terminal qui affiche les sorties de ton programme. Tu peux le faire depuis une autre session terminale locale ou depuis une connexion ssh distante. Une autre combine si tu ne veux pas avoir à chercher le pid du programme à chaque fois, c’est de l’écrire dans un fichier temporaire au démarrage du programme et écrire un petit batch qui le récupèrerait et lancerait ta bonne commande kill pour arrêter ton programme. Quand tu en seras au stade de la daemonisation, tu verras que ce n’est qu’une idée simplifiée de ce qui se fait normalement. (l’instruction pour récupèrer le pid dans un prog python est dans les exemple : ‘os.getpid()’ )
Le premier ennemi de la connaissance n’est pas l’ignorance, c’est l’illusion de la connaissance (S. Hawking).