1. ホーム
  2. バッシュ

[解決済み】プロセスが死んだら再起動するbashスクリプトはどう書けばいい?

2022-03-31 05:08:52

質問

キューをチェックし、各アイテムにアクションを実行する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ファイルは非常に有名ですが、非常に欠陥のあるものでもあり、正しい方法で行わない理由はありません。

これを考えてみましょう。

  1. 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 .
  2. PIDファイルが古くなる。 PIDファイルが古くなっているかどうかをチェックするには 複雑すぎる(というか自明でない)ロジックが必要で そのようなロジックはまたもや 1. .

  3. 書き込み権限すらない、あるいは読み取り専用の環境であればどうでしょうか。

  4. 上の例がいかにシンプルであるかをご覧ください。 複雑化する必要は全くありません。

こちらもご覧ください。 PIDファイルは「正しい」ことをしても欠陥があるのですか?

ところで。 PIDファイルよりさらに悪いのはパースです ps ! 絶対にやってはいけないこと

  1. ps は非常に移植性が悪い。 ほとんどすべてのUNIXシステムで見かけることができますが、非標準の出力が必要な場合、その引数は大きく異なります。 そして、標準出力は人間が消費するためだけのものであり、スクリプトによる解析のためのものではありません!
  2. 構文解析 ps は、多くの誤検出を引き起こします。 例えば ps aux | grep PID の例で、今度は、誰かが、引数としてどこかの数字を使ってプロセスを開始し、それがたまたま、あなたがデーモンを見つめた PID と同じだったと想像してみてください! 二人の人間が X セッションを開始し、あなたが X を grep してあなたのセッションを終了させることを想像してみてください。 それは、あらゆる種類の悪いことです。

もし、自分でプロセスを管理したくないのであれば、プロセスのモニターとして機能する完璧なシステムがいくつか存在します。 以下のようなものがあります。 実行 例えば