[解決済み】プロセスが死んだら再起動するbashスクリプトはどう書けばいい?
質問
キューをチェックし、各アイテムにアクションを実行する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ファイルやクロンなど、子プロセスでないプロセスを評価しようとするものは避けてください。
UNIXでは、子機しか待つことができないのには、とても良い理由があります。 それを回避しようとする方法(psパース、pgrep、PIDの保存、...)は欠陥があり、穴があいているのです。 例えば いいえ .
その代わり、プロセスを監視するプロセスがプロセスの親になる必要があります。 これはどういう意味でしょうか? つまり 開始 が終了するのを確実に待つことができます。 bashでは、これは全く些細なことです。
until myserver; do
echo "Server 'myserver' crashed with exit code $?. Respawning.." >&2
sleep 1
done
上記のbashのコード片が実行されます
myserver
の中に
until
をループさせます。 最初の行は
myserver
で、それが終了するのを待ちます。 終了すると
until
はその終了ステータスをチェックする。 もし、終了ステータスが
0
つまり、何らかの方法でシャットダウンするように依頼し、それが成功したことを意味します)。 この場合、再起動する必要はありません(シャットダウンするように頼んだだけです!)。 もし、終了ステータスが
ない
0
,
until
はループ本体を実行し、STDERRにエラーメッセージを出力してループを再開します(1行目に戻る)。
1秒後
.
なぜ1秒待つのか? の起動シーケンスに何か問題があった場合、その原因を突き止めるためです。
myserver
で、すぐにクラッシュしてしまうと、常に再起動とクラッシュの非常に集中的なループを手にしてしまうことになります。 そのため
sleep 1
は、その負担を軽減してくれます。
あとはこのbashスクリプトを(おそらく非同期で)起動するだけで、このスクリプトが
myserver
を作成し、必要に応じて再起動します。 起動時にモニタを開始したい場合 (サーバを "sive"再起動させたい場合)、ユーザの cron(1) で
@reboot
ルールがあります。 cronルールを開くには
crontab
:
crontab -e
次に、モニタースクリプトを起動するためのルールを追加します。
@reboot /usr/local/bin/myservermonitor
あるいは、inittab(5) と /etc/inittab を見てください。 そこに一行追加して
myserver
が特定の init レベルで開始され、自動的にリスポーンします。
編集する
理由について補足します ではなく PIDファイルを使用することです。 PIDファイルは非常に有名ですが、非常に欠陥のあるものでもあり、正しい方法で行わない理由はありません。
これを考えてみましょう。
-
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 と同じだったと想像してみてください! 二人の人間が X セッションを開始し、あなたが X を grep してあなたのセッションを終了させることを想像してみてください。 それは、あらゆる種類の悪いことです。
もし、自分でプロセスを管理したくないのであれば、プロセスのモニターとして機能する完璧なシステムがいくつか存在します。 以下のようなものがあります。 実行 例えば
関連
-
[解決済み] Bashスクリプトのソースディレクトリをスクリプト自体から取得するにはどうすればよいですか?
-
[解決済み] Bashシェルスクリプトでディレクトリが存在するかどうかを確認するにはどうすればよいですか?
-
[解決済み] Bashで通常のファイルが存在しないかどうかを判断する方法を教えてください。
-
[解決済み] Bashで文字列変数を連結する方法
-
[解決済み] Bashで文字列が部分文字列を含むかどうかをチェックする方法
-
[解決済み] Bashスクリプトからプログラムが存在するかどうかを確認するにはどうすればよいですか?
-
[解決済み] Bashで文字列をデリミターで分割するには?
-
[解決済み] Bashでコマンドライン引数を解析するには?
-
[解決済み] LinuxのシェルスクリプトでYes/No/Cancelの入力を促すにはどうしたらいいですか?
-
[解決済み] Bashシェルスクリプトの入力引数の存在確認
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】予期しないトークン 'fi' 付近の構文エラー
-
[解決済み] MacOSのbashターミナルでexport PS1="\u[\033[m]@[\033[32m]\h:\[\033[33;1m]\w[\033[m]\$" は何を意味していますか?
-
[解決済み] /bin/sh: apt-get: 見つかりません。
-
[解決済み] etc/profileでVISIBLE=NOWを設定するのはなぜですか?
-
[解決済み] スクリプトからのエラーメッセージを含むすべての端末出力をログファイルにパイプする方法
-
[解決済み] bashでjsonファイルを解析するためにjqの出力からダブルクオートを削除する方法は?
-
[解決済み] シンプルなAsciiテーブルをCSVに変換する【終了】。
-
[解決済み] bash スクリプトを実行している docker エントリポイントに "permission denied" が表示される。
-
[解決済み] ファイル内の大文字・小文字を区別しない文字列を grep するには?
-
[解決済み] Bash - "fi ;;" の使い方は?