J'ai le programme Python suivant en cours d'exécution dans un conteneur Docker.
Fondamentalement, si le processus Python se termine correctement (par exemple lorsque j'arrête manuellement le conteneur) ou si le processus Python plante (à l'intérieur de some_other_module.do_work () ), alors je dois faire un nettoyage et envoyez un ping à ma base de données pour lui dire que le processus est terminé.
Quelle est la meilleure façon d'y parvenir? J'ai vu une réponse où ils ont fait un essai de capture sur main () , mais cela semble un peu étrange.
Mon code:
def main():
some_other_module.do_work()
if __name__ == '__main__':
main()
4 Réponses :
Le Try-catch sur main semble le plus simple, mais ne fonctionne pas / peut ne pas fonctionner pour la plupart des choses (voir les commentaires ci-dessous) Vous pouvez toujours sauf exceptions spécifiques:
def main():
some_other_module.do_work()
if __name__ == '__main__':
try:
main()
except Exception as e:
if e == "<INSERT GRACEFUL INTERRUPT HERE>":
# finished gracefully
else:
print(e)
# crash
Cela ne fonctionnera pas (dans la plupart des cas). Par exemple. essayez de placer le code qui sépare les défauts dans un essayez / sauf . Ce sera inutile.
Je suppose que le nettoyage supplémentaire sera effectué par un processus différent, car le processus principal s'est probablement écrasé d'une manière non récupérable (j'ai compris la question de cette manière).
Le moyen le plus simple serait que le processus principal place un indicateur quelque part (peut-être crée un fichier à un emplacement spécifié, ou une valeur de colonne dans une table de base de données; peut également inclure le PID du processus principal qui définit l'indicateur) lorsque il démarre et supprime (ou annule) ce même indicateur s'il se termine correctement.
Le processus de nettoyage a juste besoin de vérifier l'indicateur:
Intéressant, donc, un processus pour surveiller le processus. Cela pourrait certainement fonctionner et semble être une bonne solution. Donc, fondamentalement - 1) démarrer le processus principal 2) le processus principal écrit dans le fichier avec pid 3) le processus principal engendre le processus de surveillance 4) surveiller les sondages de processus pour vérifier si le processus principal s'est écrasé en fonction du PID dans le fichier. Est-ce que je comprends bien?
Oui, c'est une façon. Ou bien, le processus de surveillance pourrait être lancé par quelqu'un d'autre: peut-être qu'un cronjob lance le moniteur toutes les 5 minutes ou quelque chose comme ça, selon votre cas d'utilisation.
Donc, j'ai réfléchi un peu plus à cela et la solution ne fonctionne en fait pas pour le cas où j'arrête le conteneur Docker contenant les deux processus. Le conteneur contiendrait à la fois le moniteur et le processus principal. Mais, lorsque vous arrêtez le conteneur, les deux seront tués!
Vous pouvez placer ce script de surveillance sur un autre conteneur et laisser l'indicateur être dans un troisième conteneur, mais ce schéma échouera également si, par exemple, une météorite frappe le centre de données qui contient tous vos conteneurs docker.
Mon point est qu'il n'y a pas de solution parfaite, mais vous devez décider du niveau de résilience dont vous avez besoin.
J'ai fini par créer une solution comme celle-ci qui conserve simplement une liste de aliveIds et interroge constamment chaque conteneur pour vérifier si ce processus est toujours en cours d'exécution. Si ce n'est pas le cas, le programme s'est arrêté et nous pouvons faire le nettoyage de ce processus. Merci de votre aide!
Utilisez un try/except
def thing_that_crashes():
exit()
try:
thing_that_crashes()
except:
print('oh and by the way, that thing tried to kill me')
Je pense qu'il est impossible d'attraper un processus avec un comportement suicidaire avancé (je ne sais pas envoyer un SYGKILL à lui-même ou quelque chose) donc si vous avez besoin de votre processus principal pour vivre quoi qu'il arrive, exécutez peut-être l'autre dans un sous-processus.
Vous pouvez envelopper votre script avec un autre script de sous-processus et vérifier le returncode . Inspiré par cette question pertinente.
from subprocess import Popen
script = Popen("python abspath/to/your/script.py")
script.communicate()
if script.returncode <> 0:
# something went wrong
# do something about it
très belle réponse !! :)
Combien de détection souhaitez-vous effectuer? Détecter une exception est facile. La détection d'une erreur du système d'exploitation peut être plus délicate. Détecter une panique du noyau ou une panne critique est difficile. Détecter quelqu'un qui débranche physiquement la machine est quasiment impossible sans matériel spécial.
Intéressé par votre cas d'utilisation @farza - vous attendez-vous à un crash, de cause connue?
Un processus ne devrait en aucun cas planter. Si c'est le cas, le code n'est pas correctement écrit et essayer de résoudre le problème à ce niveau consiste simplement à "couvrir la saleté". Avez-vous un exemple concret? Sinon, cela semble être un problème XY .
Dans notre cas,
some_other_module.do_work ()peut générer une erreur après avoir été exécuté pendant un certain temps. Il s'agit essentiellement de lire un flux vidéo, et lorsque ce flux se termine, le processus Python se termine facilement (Case1). Mais, il y a des cas où des exceptions peuvent se produire lors de la lecture de ce flux et nous ne pouvons pas quitter gracieusement (cas 2). Le troisième cas est celui où nous arrêtons simplement le conteneur Docker et le processus Python se termine correctement (cas 3)Qu'entendez-vous par " nous ne pouvons pas quitter gracieusement (cas 2) "? S'il y a une exception lors de la gestion du flux et que le programme se termine, il doit renvoyer un code de sortie non 0 . Si tel est le cas, vérifier son code de sortie (s'il n'est plus en cours d'exécution) ferait l'affaire.