web-dev-qa-db-fra.com

Exécuter le travail cron uniquement s'il ne l'est pas déjà

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.

115
LorenVS

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.

110
jjclarkson

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
95
Jess

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}"
58
rsanden

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)

22
Earlz

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.

18
Bedi Egilmez

Vous pouvez également le faire directement dans votre crontab:

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

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é.

5
Byron Whitlock

La façon dont je le fais quand j'exécute des scripts php est:

La crontab:

* * * * * php /path/to/php/script.php &

Le code 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.

4
talsibony

Je recommanderais d'utiliser un outil existant tel que monit , il surveillera et redémarrera automatiquement les processus. Il y a plus d'informations disponibles ici . Il devrait être facilement disponible dans la plupart des distributions.

3
Zitrax

Avec lockrun vous n'avez pas besoin d'écrire un script wrapper pour votre travail cron. http://www.unixwiz.net/tools/lockrun.html

3
Aaron C. de Bruyn

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>
2
DJV
# 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
}
1
ekerner

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.

1
dbenton

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'
1
lingeshram

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.

0
Richard Thomas