J'ai un script python qui vérifie une file d'attente et effectue une action sur chaque élément:
# checkqueue.py
while True:
check_queue()
do_something()
Comment puis-je écrire un script bash qui vérifiera s'il est en cours d'exécution, et si ce n'est pas le cas, démarrez-le. En gros, le pseudo-code suivant (ou peut-être devrait-il faire quelque chose comme ps | grep
?):
# keepalivescript.sh
if processidfile exists:
if processid is running:
exit, all ok
run checkqueue.py
write processid to processidfile
Je vais appeler ça depuis une crontab:
# crontab
*/5 * * * * /path/to/keepalivescript.sh
Évitez les fichiers PID, les fichiers crons ou toute autre chose qui tente d'évaluer des processus qui ne sont pas leurs enfants.
Il y a une très bonne raison pour laquelle, sous UNIX, vous ne pouvez attendre que vos enfants. Toute méthode (ps analyse, pgrep, stockage d'un PID, ...) qui tente de contourner le problème est défectueuse et comporte des trous béants. Dites simplement non .
Au lieu de cela, vous avez besoin que le processus qui surveille votre processus soit le parent du processus. Qu'est-ce que ça veut dire? Cela signifie que seul le processus que commence votre processus peut attendre de manière fiable qu'il se termine. En bash, c'est absolument trivial.
until myserver; do
echo "Server 'myserver' crashed with exit code $?. Respawning.." >&2
sleep 1
done
Le code de bash ci-dessus exécute myserver
dans une boucle until
. La première ligne commence myserver
et attend la fin. Quand il se termine, until
vérifie son statut de sortie. Si le statut de sortie est 0
, cela signifie qu'il s'est terminé normalement (ce qui signifie que vous avez demandé de l'éteindre d'une manière ou d'une autre et que l'opération s'est bien déroulée). Dans ce cas, nous ne voulons pas le redémarrer (nous lui avons simplement demandé de l'éteindre!). Si le statut de sortie est , not 0
, until
exécute le corps de la boucle, qui émet un message d'erreur sur STDERR et relance la boucle (retour à la ligne). 1) après 1 seconde .
Pourquoi attendons-nous une seconde? Parce que si quelque chose ne va pas avec la séquence de démarrage de myserver
et que celle-ci se bloque immédiatement, vous aurez une boucle très intensive de redémarrage et de plantage constants. Le sleep 1
enlève la tension.
Il ne vous reste plus qu'à démarrer ce script bash (probablement de manière asynchrone). Il surveillera myserver
et le redémarrera si nécessaire. Si vous souhaitez démarrer le moniteur au démarrage (pour que le serveur "survivre" au redémarrage), vous pouvez le planifier dans le cron de votre utilisateur avec une règle @reboot
. Ouvrez vos règles cron avec crontab
:
crontab -e
Ajoutez ensuite une règle pour démarrer votre script de moniteur:
@reboot /usr/local/bin/myservermonitor
Alternativement Regardez inittab (5) et/etc/inittab. Vous pouvez y ajouter une ligne pour que myserver
démarre à un certain niveau d'init et soit réapparu automatiquement.
Modifier.
Permettez-moi d'ajouter quelques informations sur les raisons pour lesquelles pas d'utiliser des fichiers PID. Bien qu'ils soient très populaires; ils sont également très imparfaits et il n'y a aucune raison pour que vous ne le fassiez pas correctement.
Considère ceci:
Recyclage PID (élimination du mauvais processus):
/etc/init.d/foo start
: démarrer foo
, écrire le PID de foo
dans /var/run/foo.pid
foo
meurt en quelque sorte.bar
) prend un PID aléatoire, imaginez-le en prenant l'ancien PID de foo
.foo
est parti: /etc/init.d/foo/restart
lit /var/run/foo.pid
, vérifie s'il est toujours en vie, trouve bar
, pense que c'est foo
, le tue, lance un nouveau foo
.Les fichiers PID sont périmés. Vous avez besoin d'une logique trop compliquée (ou devrais-je dire, non triviale) pour vérifier si le fichier PID est périmé, et une telle logique est à nouveau vulnérable à 1.
.
Que se passe-t-il si vous n'avez même pas d'accès en écriture ou si vous êtes dans un environnement en lecture seule?
C'est une complication inutile. voyez comme mon exemple ci-dessus est simple. Pas besoin de compliquer cela du tout.
Voir aussi: Les fichiers PID sont-ils toujours défectueux quand on le fait 'bien'?
Au fait; encore pire que les fichiers PID, c'est l'analyse ps
! Ne faites jamais cela.
ps
est très instable. Alors que vous le trouvez sur presque tous les systèmes UNIX; ses arguments varient grandement si vous voulez une sortie non standard. Et la sortie standard est UNIQUEMENT destinée à la consommation humaine et non à l'analyse syntaxique!ps
conduit à beaucoup de faux positifs. Prenons l'exemple ps aux | grep PID
et imaginons maintenant que quelqu'un lance un processus avec un nombre quelque part comme argument qui est identique au PID avec lequel vous avez surveillé votre démon! Imaginez que deux personnes commencent une session X et que vous cherchiez X à tuer la vôtre. C'est juste toutes sortes de mauvaises.Si vous ne voulez pas gérer le processus vous-même; Il existe de très bons systèmes qui serviront de moniteur pour vos processus. Regardez dans runit , par exemple.
Regardez monit ( http://mmonit.com/monit/ ). Il gère le démarrage, l'arrêt et le redémarrage de votre script et peut effectuer des vérifications de l'état et des redémarrages si nécessaire.
Ou faites un script simple:
while true
do
/your/script
sleep 1
done
La façon la plus simple de le faire consiste à utiliser flock on file. Dans le script Python, vous feriez
lf = open('/tmp/script.lock','w')
if(fcntl.flock(lf, fcntl.LOCK_EX|fcntl.LOCK_NB) != 0):
sys.exit('other instance already running')
lf.write('%d\n'%os.getpid())
lf.flush()
Dans Shell, vous pouvez réellement tester son fonctionnement:
if [ `flock -xn /tmp/script.lock -c 'echo 1'` ]; then
echo 'it's not running'
restart.
else
echo -n 'it's already running with PID '
cat /tmp/script.lock
fi
Mais bien sûr, vous n'avez pas à tester, car s'il est déjà lancé et que vous le redémarrez, il se terminera avec 'other instance already running'
À la fin du processus, tous les descripteurs de fichier sont fermés et tous les verrous sont automatiquement supprimés.
Vous devez utiliser monit, un outil standard Unix capable de surveiller différents éléments du système et de réagir en conséquence.
À partir de la documentation: http://mmonit.com/monit/documentation/monit.html#pid_testing
vérifier le processus checkqueue.py avec pidfile /var/run/checkqueue.pid si modifié pid puis exec "checkqueue_restart.sh"
Vous pouvez également configurer monit pour qu'il vous envoie un e-mail lors d'un redémarrage.
if ! test -f $PIDFILE || ! psgrep `cat $PIDFILE`; then
restart_process
# Write PIDFILE
echo $! >$PIDFILE
fi
Je ne sais pas si c'est portable sur tous les systèmes d'exploitation, mais vous pouvez vérifier si votre système contient la commande 'run-one', c'est-à-dire "man run-one". Plus précisément, cet ensemble de commandes inclut "run-one-constant", ce qui semble être exactement ce dont vous avez besoin.
De la page de manuel:
run-one-constant COMMAND [ARGS]
Remarque: ceci peut évidemment être appelé depuis votre script, mais évite également d'avoir un script.
J'ai utilisé le script suivant avec un grand succès sur de nombreux serveurs:
pid=`jps -v | grep $INSTALLATION | awk '{print $1}'`
echo $INSTALLATION found at PID $pid
while [ -e /proc/$pid ]; do sleep 0.1; done
remarques:
$INSTALLATION
contient suffisamment de chemin du processus qui est totalement non ambiguCe script est en fait utilisé pour arrêter une instance en cours d'exécution de Tomcat, que je veux fermer (et attendre) sur la ligne de commande. Par conséquent, le lancer en tant que processus enfant n'est tout simplement pas une option pour moi.