180 votes

Lancer une tâche cron uniquement si elle n'est pas déjà en cours d'exécution

J'essaie de mettre en place une tâche cron comme une sorte de chien de garde pour un démon que j'ai créé. Si le démon se trompe et échoue, je veux que le travail cron le redémarre périodiquement... Je ne suis pas sûr que cela soit possible, mais j'ai lu quelques tutoriels sur les cron et je n'ai rien trouvé qui puisse faire ce que je cherche...

Mon démon est lancé à partir d'un script shell script, donc je cherche simplement un moyen d'exécuter une tâche cron UNIQUEMENT si l'exécution précédente de cette tâche n'est pas encore en cours.

J'ai trouvé ce post qui a fourni une solution pour ce que j'essaie de faire en utilisant des fichiers de verrouillage, mais je ne suis pas sûr qu'il y ait une meilleure façon de le faire...

129voto

jjclarkson Points 3370

Je fais cela pour un programme de spooler d'impression que j'ai écrit, c'est juste un shell script :

#!/bin/sh
if ps -ef | grep -v grep | grep doctype.php ; then
        exit 0
else
        /home/user/bin/doctype.php >> /home/user/bin/spooler.log &
        #mailing program
        /home/user/bin/simplemail.php "Print spooler was not running...  Restarted." 
        exit 0
fi

Il fonctionne toutes les deux minutes et est assez efficace. Si, pour une raison quelconque, le processus ne fonctionne pas, il m'envoie un courriel contenant des informations spéciales.

4 votes

Ce n'est pas une solution très sûre, cependant, que se passe-t-il s'il y a d'autres processus qui correspondent à la recherche que vous avez faite dans grep ? La réponse de rsanden évite ce genre de problème en utilisant un fichier pid.

17 votes

Cette roue a déjà été inventée ailleurs :) Par exemple, serverfault.com/a/82863/108394

5 votes

Au lieu de grep -v grep | grep doctype.php vous pouvez faire grep [d]octype.php .

65voto

rsanden Points 391

Comme d'autres l'ont dit, écrire et vérifier un fichier PID est une bonne solution. Voici mon implémentation bash :

#!/bin/bash

mkdir -p "$HOME/tmp"
PIDFILE="$HOME/tmp/myprogram.pid"

if [ -e "${PIDFILE}" ] && (ps -u $(whoami) -opid= |
                           grep -P "^\s*$(cat ${PIDFILE})$" &> /dev/null); then
  echo "Already running."
  exit 99
fi

/path/to/myprogram > $HOME/tmp/myprogram.log &

echo $! > "${PIDFILE}"
chmod 644 "${PIDFILE}"

3 votes

+1 En utilisant un pidfile, c'est probablement plus sûr que de chercher un programme en cours d'exécution avec le même nom.

0 votes

/chemin/vers/myprogramme & > $HOME/tmp/myprogramme.log & ? ????? vouliez-vous peut-être dire /chemin/vers/myprogramme >> $HOME/tmp/myprogramme.log &

1 votes

Le fichier ne devrait-il pas être supprimé lorsque le script se termine ? Ou est-ce que je rate quelque chose de très évident ?

28voto

Earlz Points 19355

N'essayez pas de le faire via cron. Faites en sorte que cron exécute un script quoi qu'il arrive, puis faites en sorte que le script décide si le programme est en cours d'exécution et le lance si nécessaire (notez que vous pouvez utiliser Ruby ou Python ou votre langage de script préféré pour faire cela).

7 votes

La méthode classique consiste à lire un fichier PID que le service crée lorsqu'il démarre, à vérifier si le processus portant ce PID est toujours en cours d'exécution, et à le redémarrer si ce n'est pas le cas.

9voto

quezacoatl Points 31

Vous pouvez également le faire en une seule ligne directement dans votre crontab :

* * * * * [ `ps -ef|grep -v grep|grep <command>` -eq 0 ] && <command>

5 votes

Pas très sûr, et s'il y a d'autres commandes qui correspondent à la recherche de grep ?

1 votes

Cela pourrait aussi s'écrire comme suit : * * * * * [ ps -ef|grep [c]ommand -eq 0 ] && <commande> où le fait de mettre la première lettre de votre commande entre parenthèses l'exclut des résultats de grep.

0 votes

J'ai dû utiliser la syntaxe suivante : [ "$(ps -ef|grep [c]ommand|wc -l)" -eq 0 ] && <command>

6voto

Byron Whitlock Points 29863

Pour faire suite à la réponse d'Earlz, vous avez besoin d'un wrapper script qui crée un fichier $PID.running quand il démarre, et le supprime quand il se termine. Le wrapper script appelle le script que vous souhaitez exécuter. Le wrapper est nécessaire au cas où le script cible échoue ou se trompe, le fichier pid est supprimé .

0 votes

Oh cool... Je n'avais jamais pensé à utiliser un wrapper... Je n'ai pas trouvé le moyen de le faire en utilisant des fichiers de verrouillage parce que je ne pouvais pas garantir que le fichier serait supprimé si le démon se trompait... Un wrapper fonctionnerait parfaitement, je vais essayer la solution de jjclarkson, mais je ferai ceci si ça ne fonctionne pas...

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X