inotifywaitを使用した緊急事態の監視

inotifywaitを使用した緊急事態の監視

を通過するサービスがありますrsync。これが起こったら、サーバー側プログラムの実行をトリガーしたいと思います。

このコマンドのおかげで、inotifywaitファイルやディレクトリの変更を監視するのは非常に簡単です。しかし、私は通知を受けたいです。バーストを一度だけ修正してください。これは、アップロード後のプロセスが重く変更されたすべてのファイルに対してこれを実行したくないためです。

イベントタイムスタンプに基づいていくつかのハッキングを思い出すのは大きな努力ではありません...しかし、私はこれがかなり一般的な問題だと思います。しかし、私は役に立つものが見つかりませんでした。

突然の問題を解決するための奇妙なコマンドがありますか?私は次のように使用できることを考えています。

inotifywait -m "$dir" $opts | detect_burst --execute "$post_upload"

答え1

自分の回答に従ってシェルを使用したい場合は、タイムアウト時に戻りコードを> 128に設定するタイムアウトオプションをread利用できます。-tたとえば、burstスクリプトはおおよそ次のようになります。

interval=$1; shift
while :
do  if read -t $interval
    then    echo "$REPLY"            # not timeout
    else    [ $? -lt 128 ] && exit   # eof
            "$@"
            read || exit    # blocking read infinite timeout
            echo "$REPLY"
    fi
done

最初にバーストの終わりを検出したくない場合は、初期ブロッキング読み出しから開始することをお勧めします。

答え2

OP はここにあります。

私が思いついた解決策は次のプログラムですburst

inotifywait -e moved_to "$monitored_dir" -m \
    | burst 2 'echo run post-upload'

スクリプトburst:

#!/bin/bash

help() {
    >&2 echo "Usage: $0 <interval> <command>"
}

set -e
trap help EXIT
interval=${1:?missing interval}; shift
: ${1:?missing command}

trap - EXIT
set +e
exec 3> >(sed "s/^/burst: /" >&2)
while read line; do
    echo "$line" >&3
    test -n "$!" && kill -term $! 2>/dev/null
    (sleep $interval && $SHELL -c "$*") &
done

デフォルトでは、これは実際のコマンド()を実行する前に定義された時間待機するサブシェルを生成します(sleep $interval && $SHELL -c "$*")。新しく読み取った行は、対応するinotifywaitシェル(存在する場合)を終了して再生成します。

一連の行が終了すると、シェルが終了し、sleepコマンドが実行されます。

いくつかの欠点があります。

  1. stdinの各行のプロセスを終了して生成します。これは最初に行数を減らしたいという意味です(したがって-e moved_toフィルタ inotifywait)。アップロードされたファイルの数が多すぎると、WRTパフォーマンスを余裕がありません!

  2. 数秒後$interval(またはファイル転送に時間がかかります)、2番目のバーストが発生すると、実行中の更新後にプロセスが終了する可能性が高くなります。そのようなプロセスが等級であるかトランザクションであれば大丈夫です...ので注意してください。

答え3

マスター。考えられる解決策は次のとおりです。

inotifywait -m "$dir" -e moved_to --timefmt='%s' --format '%T' | stdbuf -oL uniq | ...

編集する: IMHO 2番目の答えが良いので、この質問に対する他の答えを参照してください。

move_to単一ファイル転送の最後のステップである各実行時に、epoch以降の時間を印刷して機能します。

アップロードが1秒以上続く場合でも、アップロード後にプロセスを複数回実行できますが、この方法は正常に機能します。

--timefmtフラグを別の値に変更すると、異なる粒度が得られます。

あまり気に入らないけど、半分いい考えでここに投稿します…それでも共有したかったです。

答え4

現在時刻を確認し、前のイベントと同じ(またはより一般的に定義できる方法で同様の)イベントをスキップするループを作成できます。 bash、ksh、またはzshでは、次の単純なループは10秒以内に繰り返されるイベントをスキップします。

inotifywait -m … | {
  previous_SECONDS=0
  previous_event=
  while IFS= read -r event; do
    if [[ "$event" = "$previous_event" && $SECONDS <= $previous_SECONDS + 10 ]]; then
      continue
    fi
    previous_SECONDS=$SECONDS previous_event=$event
    "$post_upload" "$event"
  done
}

シェルは高性能のテキスト処理には悪いので、他のツールを使用することをお勧めします。歴史的な理由から、時間(エポック以降の秒)を公開する非常に奇妙な方法があるawkを使用できます。呼び出しはsrand()最後の呼び出しを返しますsrand()

inotifywait -m … | awk '
    {srand(); current_time = srand()}
    $0 == previous_event && current_time <= previous_time + 10 {
        system(ENVIRON["post_upload"])
    }
    {previous_event = $0; previous_time = current_time}
'

移植性が必ずしも必要でない場合は、移植性を放棄し、Perl、Python、Rubyなどのより高いレベルのスクリプト言語を使用します。これらの言語にはすべてinotifyインタフェースがあるため、呼び出してinotifywaitテキスト解析を実行する必要はありません。

関連情報