Supposons que nous ayons un démon aussi trivial écrit en python:
def mainloop():
while True:
# 1. do
# 2. some
# 3. important
# 4. job
# 5. sleep
mainloop()
et nous le démonisons en utilisant start-stop-daemon
ce qui, par défaut, envoie le signal SIGTERM
( TERM
) --stop
.
Supposons que l'étape en cours soit #2
. Et en ce moment même, nous envoyons un TERM
signal.
Ce qui se passe, c'est que l'exécution se termine immédiatement.
J'ai trouvé que je peux gérer l'événement signal en utilisant, signal.signal(signal.SIGTERM, handler)
mais le fait est qu'il interrompt toujours l'exécution en cours et passe le contrôle à handler
.
Donc, ma question est - est-il possible de ne pas interrompre l'exécution en cours mais de gérer le TERM
signal dans un thread séparé (?) Afin que je puisse régler de shutdown_flag = True
manière à mainloop()
avoir une chance de s'arrêter gracieusement?
signalfd
et en masquant la livraison duSIGTERM
processus.Réponses:
Une solution propre à utiliser basée sur la classe:
la source
False
valeur n'est définie qu'une seule fois, puis elle ne peut passer de False à True que l'accès multiple n'est pas un problème.Tout d'abord, je ne suis pas certain que vous ayez besoin d'un deuxième fil pour définir le
shutdown_flag
.Pourquoi ne pas le définir directement dans le gestionnaire SIGTERM?
Une alternative est de lever une exception du
SIGTERM
gestionnaire, qui sera propagée dans la pile. En supposant que vous ayez une gestion des exceptions appropriée (par exemple avecwith
/contextmanager
et destry: ... finally:
blocs), cela devrait être un arrêt assez gracieux, similaire à celui de Ctrl+Cvotre programme.Exemple de programme
signals-test.py
:Maintenant, voyez le Ctrl+Ccomportement:
Cette fois je l'envoie
SIGTERM
après 4 itérations aveckill $(ps aux | grep signals-test | awk '/python/ {print $2}')
:Cette fois, j'active mon
SIGTERM
gestionnaire personnalisé et je l'envoieSIGTERM
:la source
Je pense que vous êtes proche d'une solution possible.
Exécutez
mainloop
dans un thread séparé et étendez-le avec la propriétéshutdown_flag
. Le signal peut être capturésignal.signal(signal.SIGTERM, handler)
dans le fil principal (pas dans un fil séparé). Le gestionnaire de signal doit être définishutdown_flag
sur True et attendre la fin du thread avecthread.join()
la source
Voici un exemple simple sans threads ni classes.
la source
Sur la base des réponses précédentes, j'ai créé un gestionnaire de contexte qui protège de sigint et sigterm.
la source
Trouvé le moyen le plus simple pour moi. Voici un exemple avec fork pour plus de clarté que cette façon est utile pour le contrôle de flux.
la source
La solution la plus simple que j'ai trouvée, en s'inspirant des réponses ci-dessus, c'est
la source