J'essaie donc de configurer un travail cron comme une sorte de chien de garde pour un démon que j'ai créé. Si le démon échoue et échoue, je souhaite que le travail cron le relance périodiquement ... Je ne sais pas si c'est possible, mais j'ai lu quelques tutoriels cron et je n'ai rien trouvé qui puisse faire ce que je voulais. cherche ...
Mon démon est démarré à partir d'un script Shell. Je cherche donc vraiment un moyen d'exécuter un travail cron UNIQUEMENT si l'exécution précédente de ce travail n'est pas encore en cours d'exécution.
J'ai trouvé ce post , qui a fourni une solution à ce que j'essaie de faire en utilisant des fichiers de verrouillage, mais je ne suis pas sûr qu'il existe un meilleur moyen de le faire ...
Merci de votre aide.
Je le fais pour un programme de spouleur d'impression que j'ai écrit, il ne s'agit que d'un script Shell:
#!/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. Je l'ai envoyé par courrier électronique avec des informations spéciales si, pour une raison quelconque, le processus ne fonctionne pas.
Utilisez flock
. C'est nouveau. C'est mieux.
Maintenant, vous n'avez pas à écrire le code vous-même. Découvrez plus de raisons ici: https://serverfault.com/a/8286
/usr/bin/flock -n /tmp/my.lockfile /usr/local/bin/my_script
Comme d’autres l’ont dit, l’écriture et la vérification d’un fichier PID est une bonne solution. Voici ma mise en œuvre 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}"
N'essayez pas de le faire via cron. Demandez à cron d'exécuter un script à tout moment, puis laissez le script décider si le programme est en cours d'exécution et démarrez-le si nécessaire (notez que vous pouvez utiliser Ruby ou Python = ou votre langage de script préféré pour le faire)
Il est surprenant que personne ne mentionne à propos de run-one . J'ai résolu mon problème avec ça.
apt-get install run-one
puis ajouter run-one
avant votre script crontab
*/20 * * * * * run-one python /script/to/run/awesome.py
Découvrez this askubuntu SE réponse. Vous pouvez également trouver un lien vers une information détaillée.
Vous pouvez également le faire directement dans votre crontab:
* * * * * [ `ps -ef|grep -v grep|grep <command>` -eq 0 ] && <command>
Pour faire suite à Earlz answer, vous avez besoin d’un script de wrapper qui crée un fichier $ PID.running à son démarrage et supprime à la fin. Le script wrapper appelle le script que vous souhaitez exécuter. Le wrapper est nécessaire en cas d'échec du script cible ou d'erreur de sortie, le fichier pid est supprimé.
La façon dont je le fais quand j'exécute des scripts php est:
* * * * * php /path/to/php/script.php &
<?php
if (Shell_exec('ps aux | grep ' . __FILE__ . ' | wc -l') > 1) {
exit('already running...');
}
// do stuff
Cette commande recherche dans la liste des processus système le nom de fichier php actuel s'il existe. Le compteur de lignes (wc -l) sera supérieur à un, car la commande de recherche elle-même contient le nom de fichier.
donc, si vous exécutez php crons, ajoutez le code ci-dessus au début de votre code php et il ne sera exécuté qu'une fois.
Avec lockrun
vous n'avez pas besoin d'écrire un script wrapper pour votre travail cron. http://www.unixwiz.net/tools/lockrun.html
Celui-ci ne m'a jamais manqué:
one.sh :
LFILE=/tmp/one-`echo "$@" | md5sum | cut -d\ -f1`.pid
if [ -e ${LFILE} ] && kill -0 `cat ${LFILE}`; then
exit
fi
trap "rm -f ${LFILE}; exit" INT TERM EXIT
echo $$ > ${LFILE}
$@
rm -f ${LFILE}
tâche cron :
* * * * * /path/to/one.sh <command>
# one instance only (works unless your cmd has 'grep' in it)
ALREADY_RUNNING_EXIT_STATUS=0
bn=`basename $0`
proc=`ps -ef | grep -v grep | grep "$bn" | grep -v " $$ "`
[ $? -eq 0 ] && {
pid=`echo $proc | awk '{print $2}'`
echo "$bn already running with pid $pid"
exit $ALREADY_RUNNING_EXIT_STATUS
}
Je suggérerais ce qui suit comme une amélioration de réponse de rsanden (je posterais comme commentaire, mais je n'ai pas assez de réputation ...):
#!/usr/bin/env bash
PIDFILE="$HOME/tmp/myprogram.pid"
if [ -e "${PIDFILE}" ] && (ps -p $(cat ${PIDFILE}) > /dev/null); then
echo "Already running."
exit 99
fi
/path/to/myprogram
Cela évite les éventuelles fausses correspondances (et la surcharge de grepping), supprime la sortie et repose uniquement sur l'état de sortie de ps.
Un simple php personnalisé suffit à atteindre. Pas besoin de confondre avec le script Shell.
supposons que vous vouliez exécuter php /home/mypath/example.php si vous ne le faites pas
Ensuite, utilisez le script php personnalisé suivant pour faire le même travail.
créer ce qui suit / home/mypath/forever.php
<?php
$cmd = $argv[1];
$grep = "ps -ef | grep '".$cmd."'";
exec($grep,$out);
if(count($out)<5){
$cmd .= ' > /dev/null 2>/dev/null &';
exec($cmd,$out);
print_r($out);
}
?>
Puis dans votre cron ajouter ce qui suit
* * * * * php /home/mypath/forever.php 'php /home/mypath/example.php'
Pensez à utiliser pgrep (si disponible) plutôt que ps acheminé par grep si vous voulez suivre cette voie. Bien que, personnellement, j'ai beaucoup de kilomètres de scripts de la forme
while(1){
call script_that_must_run
sleep 5
}
Bien que cela puisse échouer et créer des tâches sont souvent la meilleure façon de faire des choses essentielles. Juste une autre alternative.