web-dev-qa-db-ja.com

"while true"を使用してスクリプトを存続させることは良い考えですか?

私は別の世界からunixに飛び乗っています。

while true
do
  /someperlscript.pl
done

Perlスクリプト自体には、ターゲットの場所でファイルが変更されたときに実行されるフォルダー/ファイルウォッチャーが内部にあります。

これは (while true)良いアイデアですか?そうでない場合、好ましい堅牢なアプローチは何ですか?

TIA

編集:これはかなりの関心を生み出したようですので、これが完全なシナリオです。 Perlスクリプト自体は、ファイルウォッチャーを使用してディレクトリを監視します。新しいファイルを受信すると(rsync経由で到着します)、新しいファイルを取得して処理します。これで、着信ファイルが破損している可能性があり(質問しないでください。RaspberryPiからのもの)、プロセスで処理できない場合があります。まだすべてのシナリオを把握していないため、正確な理由はわかりません。

しかし、プロセスが何らかの理由で失敗した場合、次のファイルはエラーを引き起こした可能性のある前のファイルとは完全に無関係であるため、プロセスを稼働させて次のファイルを処理する必要があります。

通常、私は何らかのキャッチオールを使用し、コード全体をラップして、決してクラッシュしないようにしていました。しかし、Perlには確信が持てませんでした。

私が理解したことから、監視のようなものを使用することは、これのための良いアプローチです。

21
Abhinav Gujjar

それは、Perlスクリプトが返す速度に依存します。すぐに戻る場合は、CPUの負荷を回避するために、実行の間に小さな一時停止を挿入することができます。例:

while true
do
  /someperlscript.pl
  sleep 1
done

これにより、スクリプトが見つからなかったり、スクリプトがすぐにクラッシュしたりしても、CPUが独占されることはありません。

これらの問題を回避するために、Perlスクリプト自体にループを実装することをお勧めします。

編集:

ループを記述した目的は、Perlスクリプトがクラッシュした場合に再起動することだけなので、監視対象サービスとして実装するのがより良い方法ですが、その正確な方法はOSに依存します。例:Solaris smf、Linux systemdまたはcronベースのリスターター。

22
jlliagre

inotifyの使用に関する他の回答は正しいですが、この質問に対する回答ではありません。

supervisordupstartrunitなどのプロセススーパーバイザは、サービスがクラッシュした場合にサービスを監視して再起動するという問題に正確に対応するように設計されています。

ディストリビューションには、おそらくプロセススーパーバイザが組み込まれています。

14
Jacob Krall

while trueは、汎用の「永久にループする」構造として問題ありません。他の回答が言うように、ループの本体は空であってはならず、ループ内のコマンドが機能しないために空にならないようにしてください。

Linuxを使用している場合は、inotifywaitのようなコマンドを使用すると、whileループがはるかに簡単になります。

while inotifywait -qqe modify "$DIRECTORY"
do
    process_the_directory "$DIRECTORY"
done

ここで、inotifywaitコマンドは待機し、ファイルシステムイベントが発生するのを待ちます(この例では、ディレクトリ内のファイルが書き込まれるとき)。その時点で正常に終了し、ループの本体が実行されます。その後、再び待機状態に戻ります。 inotifywaitコマンドはディレクトリで何かが発生するのを待つため、継続的にディレクトリをポーリングするよりもはるかに効率的です。

11
Stuart Caie

While 1をPerlスクリプトに移動します(@roaimaの提案に従います)

#!/usr/bin/Perl

 use Linux::Inotify2;

 my $inotify = new Linux::Inotify2 or die "unable to inotify: $!";

 $inotify->watch ("Dir", IN_MODIFY, ## or in_{acess,create,open, etc...}
   sub { my $e = shift;
     my $name = $e->fullname;
     ## whatever 
     print "$name was modified\n" if $e->IN_MODIFY;
  });

 1 while $inotify->poll;
4
JJoao

Perlスクリプトが常に実行し続けることを目的としているのに、なぜwhile構文を使用するのですか?いくつかの深刻な問題を考慮してPerlが失敗すると、whileによって開始された新しいPerlスクリプトが同様にクラッシュする可能性があります。もう一度、そして再び。
Perlを最初からやり直したい場合は、crontabと、実行中のインスタンスを最初にチェックするスクリプトを検討してください。これにより、再起動後にスクリプトが開始されます。

3
Walter A

プロセスを管理したい場合は、プロセスマネージャーを調べてください。

最近の多くのシステムでは、 systemd を使用してプロセスを監視できます(これは、従来のinitスクリプトに対するsystemdの利点の1つです)。選択したディストリビューションでsystemdを使用しない場合は、 daemontools または monit を使用できます。

2
Andrew Aylett

while trueは、Perlスクリプトが終了した後にのみ実行される小さなテストであるため、通常は問題ありません。使用しているLinux/Unixバリアントによっては、ログオフ時にスクリプトが終了する場合があることに注意してください。このような場合は、スクリプトでループを使用してNohupで呼び出し、バックグラウンドに配置することを検討してください。つまり、Nohup myscript &

Perlスクリプトが頻繁に終了し、CPU負荷が発生する場合、この負荷はwhile trueではなくPerlスクリプトに責任があります。

詳細については、man Nohupもご覧ください。

2
Lambert

whileループは、実際にはお勧めできません。そこにエスケープはありません-それは永遠に実行されるだけです-静的に。環境内で多くのことが変化する可能性があり、影響はありません-これは悪いことです。

たとえば、そのwhileループを担当するシェル実行可能ファイルがアップグレードされた場合、実行中は記述子を維持する必要があるため、そのスクリプトが終了するまで、カーネルは古いバージョンのディスク領域を解放できません。 。ループを実行するために何らかの理由でシェルが開いた可能性のあるすべてのファイルについても同様です。これらのファイルはすべて、実行中の間、このwhileループによって開いたままになります。

そして、天国が禁じた場合、そのループを実行しているシェルのどこかにメモリリークがあります-たとえ最短でも-それは単にリークし続けるでしょう静的に。チェックなしでビルドされ、強制的にそれを強制終了して、後で同じことをするために最初からやり直すことが唯一の手段です。

これは、実際にはバックグラウンドプロセスをセットアップする方法ではありません。少なくとも、私の意見ではありません。代わりに、私が思うに、リセットポイント-スクリプトとその状態の更新があるはずです。これを行う最も簡単な方法は、execを使用することです。同じPIDを維持しながら、現在のプロセスを新しいプロセスに置き換えることができますが、newプロセスを実行しています。

たとえば、監視されているディレクトリでファイルの変更を正常に処理した後、Perlスクリプトがtrueを返す必要がある場合:

#!/bin/sh
trap 'rm -rf -- "${ldir%%*.}"' 0 INT
_exec() case    $#      in
        (0)     exec env -  "PID=$$" "ldir=${TMPDIR:-/tmp}/." \
                            "$0" "$@";;
        (*)     export "$@" "boff=0" "lmt=30"
                exec        "$0" "$@";;
        esac
[ "$PID" = "$$" ] || _exec
[ -w "$ldir" ]  &&
case    $ldir   in
(*.)    until   mkdir -- "$ldir"
        do      :& ldir=$ldir$$$!
        done    2>/dev/null
;;
(*)     until   /someperlscript.pl ||
                [ "$((boff+=1))"  -ge "$lmt" ]
        do      [ -d "$ldir" ]     &&
                sleep "$boff"      || ! break
        done
;;esac  &&      _exec ldir PID

...またはそのようなもの。ループの背後にある基本的な機構が時々更新されるようにするもの。

2
mikeserv

私はこれらの回答のいくつかを賛成しましたが、@ WalterAの回答には直感的に最も暖かい気持ちがあります。ええと、私は自分の答えを作成するまでしました...

個人的には、Perlスクリプトを更新して、失敗に関する説明的なログエントリを書き込み、管理者にアラートを送信するようにします。

Perlスクリプトが実行を継続し、ファイルシステムからの変更イベントを待機することを意図している場合、なぜ失敗するのですか?

それが失敗しないのであれば、それをスクリプトにラップして無限に再起動することについてなぜ心配しているのですか?

Perlスクリプトが異常終了する原因となる構成の問題またはいくつかの依存関係が壊れている場合、単純に何度も再起動しても、突然動作し始める可能性は低いです。

あなたは狂気の定義を知っていますよね? (同じことを何度も繰り返し、異なる結果を期待しています)。ただ言って。 ;-)

1
Craig