Pourquoi les processus engendrés par la fin Cron jusqu'à défunte?
-
19-09-2019 - |
Question
J'ai des processus montrant comme <defunct>
dans top
(et ps
). Je l'ai fait bouillir les choses des vrais scripts et programmes.
Dans mon crontab
:
* * * * * /tmp/launcher.sh /tmp/tester.sh
Le contenu de launcher.sh
(ce qui est bien sûr le signe exécutable):
#!/bin/bash
# the real script does a little argument processing here
"$@"
Le contenu de tester.sh
(ce qui est bien sûr le signe exécutable):
#!/bin/bash
sleep 27 & # the real script launches a compiled C program in the background
ps
montre les éléments suivants:
user 24257 24256 0 18:32 ? 00:00:00 [launcher.sh] <defunct>
user 24259 1 0 18:32 ? 00:00:00 sleep 27
Notez que tester.sh
ne semble pas -. Il a quitté après le lancement de la tâche d'arrière-plan
Pourquoi est-ce launcher.sh
rester, marqué <defunct>
? Il semble que de le faire lors de son lancement par cron
-. Pas quand je cours moi-même
Note complémentaire: launcher.sh
est un script commun dans le système fonctionne sur ce qui n'est pas facile à modifier. Les autres (crontab
, tester.sh
, même le programme que je cours au lieu de sleep
) peuvent être modiified beaucoup plus facilement.
La solution
Parce qu'ils ont pas fait l'objet d'un appel système wait(2)
.
Comme quelqu'un peut attendre que ces processus dans l'avenir, le noyau ne peut pas complètement se débarrasser d'eux ou il ne sera pas en mesure d'exécuter l'appel système wait
car il ne sera pas le statut de sortie ou la preuve de son existence plus.
Lorsque vous démarrez un de la coquille, votre coquille est le piégeage SIGCHLD et de faire diverses opérations d'attente de toute façon, rien ne reste disparu depuis longtemps.
Mais Cron est pas dans un état d'attente, il dort, pour que l'enfant défunt peut rester pendant un certain temps jusqu'à ce que se réveille Cron vers le haut.
Mise à jour: En réponse aux commentaires ... Hmm. J'ai réussi à reproduire le problème:
PPID PID PGID SESS COMMAND
1 3562 3562 3562 cron
3562 1629 3562 3562 \_ cron
1629 1636 1636 1636 \_ sh <defunct>
1 1639 1636 1636 sleep
Alors, ce qui est arrivé était, je pense:
- fourches et Cron enfant commence shell Cron
- shell (1636) commence sid et pgid 1636 et commence le sommeil
- sorties shell, SIGCHLD envoyé à 3562 cron
- signal est ignoré ou mal géré
- shell devient zombie. Notez que le sommeil est reparented à init, alors quand le sommeil sort init obtenir le signal et nettoyer. Je suis encore à essayer de comprendre quand le zombie se moissonnée. Probablement sans enfants actifs sur les chiffres 1629 cron il peut sortir, à ce moment-là le zombie sera reparented à init et se moissonnée. Alors maintenant, nous nous interrogeons sur l'SIGCHLD manquant qui Cron aurait dû traiter.
- Il est pas nécessairement la faute de cron Vixie. Comme vous pouvez le voir ici, libdaemon installe un gestionnaire de SIGCHLD pendant
daemon_fork()
, et cela pourrait interférer avec la livraison du signal sur une sortie rapide par 1629 intermédiairemaintenant, je ne sais même pas si cron Vixie sur mon Ubuntu est le système même construit avec libdaemon, mais au moins je une nouvelle théorie. :-)
- Il est pas nécessairement la faute de cron Vixie. Comme vous pouvez le voir ici, libdaemon installe un gestionnaire de SIGCHLD pendant
Autres conseils
Je soupçonne que Cron attend tous les sous-processus de la session pour terminer. Attentiste (2) par rapport aux arguments pid négatifs. Vous pouvez voir le SESS avec:
ps faxo stat,euid,ruid,tty,tpgid,sess,pgrp,ppid,pid,pcpu,comm
Voici ce que je vois (édité):
STAT EUID RUID TT TPGID SESS PGRP PPID PID %CPU COMMAND
Ss 0 0 ? -1 3197 3197 1 3197 0.0 cron
S 0 0 ? -1 3197 3197 3197 18825 0.0 \_ cron
Zs 1000 1000 ? -1 18832 18832 18825 18832 0.0 \_ sh <defunct>
S 1000 1000 ? -1 18832 18832 1 18836 0.0 sleep
Notez que le poisson et le sommeil sont dans la même ESSE.
Utilisez la commande setsid (1). Voici tester.sh:
#!/bin/bash
setsid sleep 27 # the real script launches a compiled C program in the background
Notez que vous n'avez pas besoin &
, setsid il met en arrière-plan.
à mon avis, il est causé par le processus crond (engendrés par crond pour chaque tâche) en attente pour l'entrée sur stdin qui est canalisée vers la sortie standard / stderr de la commande dans la crontab. Cela se fait parce que Cron est capable d'envoyer par courrier sortie résultant à l'utilisateur.
crond attend EOF jusqu'à ce que la commande de l'utilisateur et tout ce qu'il a donné naissance à des processus enfants ont fermé le tuyau. Si cela se fait crond se poursuit avec la déclaration d'attente puis la commande utilisateur défunt disparaît.
Alors, je pense que vous devez vous déconnecter explicitement tous les sous-processus donné naissance dans votre script forme la conduite (par exemple en le redirigeant vers un fichier ou / dev / null.
la ligne suivante devrait fonctionner dans crontab:
* * * * * ( /tmp/launcher.sh /tmp/tester.sh &>/dev/null & )
Je vous recommande de résoudre le problème simplement de ne pas avoir deux processus distincts: Avez-launcher.sh
faire sur sa dernière ligne:
exec "$@"
Cela permettra d'éliminer le processus superflu.
Je trouve cette question alors que je cherchais une solution à un problème similaire. Malheureusement, les réponses à cette question n'a pas résolu mon problème.
Tuer processus défunt n'est pas une option que vous avez besoin de trouver et de tuer son processus parent. J'ai fini par tuer les processus défunts de la manière suivante:
ps -ef | grep '<defunct>' | grep -v grep | awk '{print "kill -9 ",$3}' | sh
Dans « grep » vous pouvez restreindre la recherche à un processus défunt spécifique que vous recherchez.
Je l'ai testé le même problème tant de fois. Et enfin, j'ai la solution. Il suffit de spécifier le '/ bin / bash' avant que le script bash comme indiqué ci-dessous.
* * * * * /bin/bash /tmp/launcher.sh /tmp/tester.sh