web-dev-qa-db-ja.com

cronジョブがまだ実行されていない場合にのみ実行します

だから、私は自分が作成したデーモンの一種のウォッチドッグとしてcronジョブを設定しようとしています。デーモンがエラーになって失敗した場合、cronジョブを定期的に再起動します...これがどのように可能かはわかりませんが、cronチュートリアルをいくつか読んで、私が何をするかを見つけることができませんでした探しています...

私のデーモンはシェルスクリプトから開始されるため、そのジョブの前回の実行がまだ実行されていない場合にのみ、cronジョブを実行する方法を実際に探しています。

この投稿を見つけました 、ロックファイルを使用してやろうとしていることの解決策を提供しましたが、それを行うより良い方法があるかどうかはわかりません...

ご協力いただきありがとうございます。

115
LorenVS

私が書いた印刷スプーラープログラムに対してこれを行います。これは単なるシェルスクリプトです。

#!/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

2分ごとに実行され、非常に効果的です。何らかの理由でプロセスが実行されていない場合は、特別な情報をメールで送信します。

110
jjclarkson

flockを使用します。それは新しい。より良いです。

これで、自分でコードを記述する必要はありません。ここで他の理由を確認してください: https://serverfault.com/a/8286

/usr/bin/flock -n /tmp/my.lockfile /usr/local/bin/my_script
95
Jess

他の人が述べたように、PIDファイルの作成とチェックは良い解決策です。これが私の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

Cron経由でやろうとしないでください。 cronに何があってもスクリプトを実行させてから、プログラムが実行されているかどうかをスクリプトに判断させ、必要に応じてそれを開始させます(RubyまたはPythonまたはお好みのスクリプト言語を使用できますこれをする)

22
Earlz

run-one について誰も言及していないのは驚きです。私はこれで私の問題を解決しました。

 apt-get install run-one

run-oneをcrontabスクリプトの前に追加します

*/20 * * * * * run-one python /script/to/run/awesome.py

this askubuntu SEの回答をご覧ください。また、詳細情報へのリンクもあります。

18
Bedi Egilmez

Crontabで直接ワンライナーとして実行することもできます。

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

Earlzの回答のフォローアップとして、起動時に$ PID.runningファイルを作成し、終了時に削除するラッパースクリプトが必要です。ラッパースクリプトは、実行するスクリプトを呼び出します。ラッパーは、ターゲットスクリプトが失敗またはエラーになった場合に必要です。pidファイルは削除されます。

5
Byron Whitlock

Phpスクリプトを実行しているときの方法は次のとおりです。

Crontab:

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

PHPコード:

<?php
if (Shell_exec('ps aux | grep ' . __FILE__ . ' | wc  -l') > 1) {
    exit('already running...');
}
// do stuff

このコマンドは、システムプロセスリストで現在のphpファイル名が存在する場合に検索します。検索コマンド自体にはファイル名が含まれているため、行カウンタ(wc -l)は1より大きくなります。

したがって、php cronを実行している場合、上記のコードをphpコードの先頭に追加すると、1回だけ実行されます。

4
talsibony

monit などの既存のツールを使用することをお勧めします。これはプロセスを監視し、自動再起動します。より多くの情報が利用可能です こちら 。ほとんどのディストリビューションで簡単に利用できるはずです。

3
Zitrax

lockrunを使用すると、cronジョブのラッパースクリプトを記述する必要はありません。 http://www.unixwiz.net/tools/lockrun.html

3

これ 決して私に失敗しなかった:

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}

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

rsanden's answer の改善として以下を提案します(コメントとして投稿しますが、十分な評判はありません...):

#!/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

これにより、誤った一致(およびgreppingのオーバーヘッド)が回避され、出力が抑制され、psの終了ステータスのみに依存します。

1
dbenton

シンプルなカスタムphpで十分です。シェルスクリプトと混同する必要はありません。

実行したい場合php /home/mypath/example.php実行していない場合

次に、次のカスタムphpスクリプトを使用して同じジョブを実行します。

次を作成/ 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);
    }
?>

次に、cronに以下を追加します

* * * * * php /home/mypath/forever.php 'php /home/mypath/example.php'
1
lingeshram

そのルートを使用する場合は、psをgrepでパイプ処理するのではなく、pgrep(使用可能な場合)を使用することを検討してください。個人的には、私は次の形式のスクリプトから多くのマイレージを得ています

while(1){
  call script_that_must_run
  sleep 5
}

これは失敗する可能性がありますが、cronジョブareは、多くの場合、不可欠なものに最適な方法です。ちょうど別の選択肢。

0
Richard Thomas