キューをチェックし、各アイテムに対してアクションを実行するpythonスクリプトがあります。
# checkqueue.py
while True:
check_queue()
do_something()
実行中かどうかを確認し、実行されていない場合は起動するbashスクリプトを作成するにはどうすればよいですか。ほぼ次の擬似コード(または、ps | grep
?
# keepalivescript.sh
if processidfile exists:
if processid is running:
exit, all ok
run checkqueue.py
write processid to processidfile
これをcrontabから呼び出します。
# crontab
*/5 * * * * /path/to/keepalivescript.sh
PIDファイル、cron、またはそれらの子ではないプロセスを評価しようとする他のものは避けてください。
UNIXでは、子供だけを待つことができる非常に良い理由があります。これを回避しようとするメソッド(ps解析、pgrep、PIDの保存など)には欠陥があり、それに穴が開いています。 noとだけ言ってください。
代わりに、プロセスを監視するプロセスがプロセスの親になる必要があります。これは何を意味するのでしょうか?プロセスが終了するのを確実に待つことができるstartsプロセスのみを意味します。 bashでは、これは非常に簡単です。
until myserver; do
echo "Server 'myserver' crashed with exit code $?. Respawning.." >&2
sleep 1
done
上記のbashコードは、myserver
ループでuntil
を実行します。最初の行はmyserver
で始まり、終了するのを待ちます。終了すると、until
は終了ステータスを確認します。終了ステータスが0
の場合、正常に終了したことを意味します(つまり、何らかの方法でシャットダウンするように要求し、正常に終了したことを意味します)。その場合、再起動する必要はありません(シャットダウンするように要求しただけです!)。終了ステータスがnot0
の場合、until
はループ本体を実行し、STDERRでエラーメッセージを発行し、ループを再開します(1行目に戻る)1秒後。
なぜ私たちは一秒待つのですか?なぜなら、myserver
の起動シーケンスに問題があり、すぐにクラッシュした場合、継続的な再起動とクラッシュが非常に集中的なループになるためです。 sleep 1
は、その負担を取り除きます。
これで必要なのは、このbashスクリプトを(おそらく非同期で)起動するだけで、myserver
を監視し、必要に応じて再起動します。ブート時にモニターを開始したい場合(サーバーをリブートして「存続させる」)、@reboot
ルールを使用してユーザーのcron(1)でモニターをスケジュールできます。 crontab
を使用してcronルールを開きます。
crontab -e
次に、モニタースクリプトを開始するルールを追加します。
@reboot /usr/local/bin/myservermonitor
または、 inittab(5)と/ etc/inittabを見てください。そこに行を追加して、myserver
を特定の初期化レベルで開始し、自動的に再生成することができます。
編集。
PIDファイルを使用する理由notに関する情報を追加します。彼らは非常に人気がありますが;彼らはまた非常に欠陥があり、あなたがそれを正しい方法だけでしない理由はありません。
このことを考慮:
PIDリサイクル(間違ったプロセスを殺す):
/etc/init.d/foo start
:foo
を開始し、foo
のPIDを/var/run/foo.pid
に書き込みますfoo
はどういうわけか死にます。bar
と呼ばれる)はランダムPIDを取ります。foo
の古いPIDを取ります。foo
がなくなったことに気付きます:/etc/init.d/foo/restart
は/var/run/foo.pid
を読み取り、まだ生きているかどうかを確認し、bar
を見つけ、それがfoo
であると考え、それを殺し、新しいfoo
を開始します。PIDファイルは古くなります。 PIDファイルが古くなっているかどうかを確認するには、過度に複雑な(つまり、自明ではない)ロジックが必要であり、そのようなロジックはすべて1.
に対して脆弱です。
書き込みアクセス権がない場合、または読み取り専用環境にいる場合はどうなりますか?
それは無意味な過度の複雑さです。上記の私の例がいかに簡単かを見てください。それを複雑にする必要はまったくありません。
以下も参照してください: 「正しい」ことを行ったときにPIDファイルにまだ欠陥がありますか?
ところで; PIDファイルの解析がps
!を解析するよりもさらに悪い.
ps
は非常に移植性がありません。ほとんどすべてのUNIXシステムで使用できますが、非標準出力が必要な場合、その引数は大きく異なります。また、標準出力は、スクリプトによる解析ではなく、人間が消費するためのものです!ps
を解析すると、多くの誤検知が発生します。 ps aux | grep PID
の例を見てみましょう。誰かが、デーモンを凝視したPIDと同じである引数としてどこかでプロセスを開始することを想像してください! 2人がXセッションを開始し、Xがあなたのものを殺すことを嘆いていると想像してください。それはあらゆる種類の悪いことです。自分でプロセスを管理したくない場合;プロセスのモニターとして機能する完全に優れたシステムがいくつかあります。たとえば、 runit を調べます。
Monitをご覧ください( http://mmonit.com/monit/ )。スクリプトの開始、停止、再起動を処理し、必要に応じてヘルスチェックと再起動を実行できます。
または、簡単なスクリプトを実行します。
while true
do
/your/script
sleep 1
done
最も簡単な方法は、ファイルでflockを使用することです。 Pythonスクリプトで
lf = open('/tmp/script.lock','w')
if(fcntl.flock(lf, fcntl.LOCK_EX|fcntl.LOCK_NB) != 0):
sys.exit('other instance already running')
lf.write('%d\n'%os.getpid())
lf.flush()
Shellでは、実際に実行されているかどうかをテストできます。
if [ `flock -xn /tmp/script.lock -c 'echo 1'` ]; then
echo 'it's not running'
restart.
else
echo -n 'it's already running with PID '
cat /tmp/script.lock
fi
しかし、もちろん、テストする必要はありません。既に実行されていて再起動すると、'other instance already running'
で終了するからです。
プロセスが終了すると、すべてのファイル記述子が閉じられ、すべてのロックが自動的に削除されます。
システム上のさまざまなものを監視し、それに応じて対応できる標準のUNIXツールであるmonitを使用する必要があります。
ドキュメントから: http://mmonit.com/monit/documentation/monit.html#pid_testing
プロセスcheckqueue.pyをpidfile /var/run/checkqueue.pid でチェックし、pidが変更された場合、「checkqueue_restart.sh」 を実行します。
再起動を行うときにメールを送信するようにmonitを構成することもできます。
if ! test -f $PIDFILE || ! psgrep `cat $PIDFILE`; then
restart_process
# Write PIDFILE
echo $! >$PIDFILE
fi
オペレーティングシステム間での移植性はわかりませんが、システムに「run-one」コマンド、つまり「man run-one」が含まれているかどうかを確認することもできます。具体的には、この一連のコマンドには「1回限り実行」が含まれており、これはまさに必要なもののようです。
Manページから:
run-one-constantlyコマンド[ARGS]
注:当然、これはスクリプト内から呼び出すことができますが、スクリプトを使用する必要もなくなります。
次のスクリプトを使用して、多数のサーバーで大成功を収めました。
pid=`jps -v | grep $INSTALLATION | awk '{print $1}'`
echo $INSTALLATION found at PID $pid
while [ -e /proc/$pid ]; do sleep 0.1; done
ノート:
$INSTALLATION
には、完全に明確なプロセスパスが十分に含まれていますこのスクリプトは実際に実行中のTomcatのインスタンスをシャットダウンするために使用されます。これをコマンドラインでシャットダウン(および待機)したいので、子プロセスとして起動することは単に選択肢ではありません。