だから、私は自分が作成したデーモンの一種のウォッチドッグとしてcronジョブを設定しようとしています。デーモンがエラーになって失敗した場合、cronジョブを定期的に再起動します...これがどのように可能かはわかりませんが、cronチュートリアルをいくつか読んで、私が何をするかを見つけることができませんでした探しています...
私のデーモンはシェルスクリプトから開始されるため、そのジョブの前回の実行がまだ実行されていない場合にのみ、cronジョブを実行する方法を実際に探しています。
この投稿を見つけました 、ロックファイルを使用してやろうとしていることの解決策を提供しましたが、それを行うより良い方法があるかどうかはわかりません...
ご協力いただきありがとうございます。
私が書いた印刷スプーラープログラムに対してこれを行います。これは単なるシェルスクリプトです。
#!/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分ごとに実行され、非常に効果的です。何らかの理由でプロセスが実行されていない場合は、特別な情報をメールで送信します。
flock
を使用します。それは新しい。より良いです。
これで、自分でコードを記述する必要はありません。ここで他の理由を確認してください: https://serverfault.com/a/8286
/usr/bin/flock -n /tmp/my.lockfile /usr/local/bin/my_script
他の人が述べたように、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}"
Cron経由でやろうとしないでください。 cronに何があってもスクリプトを実行させてから、プログラムが実行されているかどうかをスクリプトに判断させ、必要に応じてそれを開始させます(RubyまたはPythonまたはお好みのスクリプト言語を使用できますこれをする)
Crontabで直接ワンライナーとして実行することもできます。
* * * * * [ `ps -ef|grep -v grep|grep <command>` -eq 0 ] && <command>
Earlzの回答のフォローアップとして、起動時に$ PID.runningファイルを作成し、終了時に削除するラッパースクリプトが必要です。ラッパースクリプトは、実行するスクリプトを呼び出します。ラッパーは、ターゲットスクリプトが失敗またはエラーになった場合に必要です。pidファイルは削除されます。
Phpスクリプトを実行しているときの方法は次のとおりです。
* * * * * php /path/to/php/script.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回だけ実行されます。
lockrun
を使用すると、cronジョブのラッパースクリプトを記述する必要はありません。 http://www.unixwiz.net/tools/lockrun.html
これ 決して私に失敗しなかった:
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>
# 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
}
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の終了ステータスのみに依存します。
シンプルなカスタム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'
そのルートを使用する場合は、psをgrepでパイプ処理するのではなく、pgrep(使用可能な場合)を使用することを検討してください。個人的には、私は次の形式のスクリプトから多くのマイレージを得ています
while(1){
call script_that_must_run
sleep 5
}
これは失敗する可能性がありますが、cronジョブareは、多くの場合、不可欠なものに最適な方法です。ちょうど別の選択肢。