タイムアウトのある通過パイプ

タイムアウトのある通過パイプ

パイプを介してデータが渡されないときにタイムアウトを実装する方法は?監視装置として機能し、次のように使用できます。

process1 | watchdog --timeout 60 | process2

データパイプが入っていないときに監視プロセスを終了したいです。

ありがとうございます!

答え1

まず、あなたの質問の監視パイプは、process1デッドパイプに書き換えようとしない限り終了しません。したがって、ウォッチドッグは何らかの方法で明示的にprocess1を終了する必要があります。

これに加えて、非常に単純なwatchdog.shシェルスクリプトがあります。コンソールで対話的にテストできます。と入力すると、./watchdog.sh入力した内容がすべてコピーされ、5秒間何も入力しないと停止します。

#!/bin/bash

# first arg is timeout (default: 5)
T="${1:-5}"
PID=$$

exec tee >(bash -c '
while true ; do
    bytes=$(timeout '$T' cat | wc -c)
    if ! [ "$bytes" -gt 0 ] ;then
            break
    fi
done
## add something like "killall process1", for now we just kill this tee command
kill -9 '$PID)

スクリプトは実際にはTと2 * Tの間でタイムアウトします(そうでなければより複雑になります)。最初に述べたように、killメソッドを何とか追加できますprocess1

以下はテストの例です。

プロセス1.sh:

#!/bin/bash

echo "here we are ..."
sleep 2
echo "still alive ..."
sleep 20
echo "too late ..."

そして、次のように実行します(タイムアウト時にprocess1.shを終了する醜い方法を含む)。

(./process1.sh & echo $! >/tmp/pid; wait) |(./watchdog.sh 5; kill `cat /tmp/pid`)

答え2

これはパフォーマンスの観点から理想的ではなく、ラインベースですが、readこの目的にはコマンドのタイムアウト機能が役に立つ可能性があります。セクションでは、bash次のコマンドラインセクションを使用できますwatchdog --timeout 60

while read -r -s -t 60 line ; do printf "%s\n" "$line" ; done

zsh同様のreadコマンドが提供されます。

process1ただし、標準出力が閉じて最初の部分(yoursなど)が終了するまで、コマンド全体が実際に終了しないことに注意してください。

答え3

問題の別の観点は、パイプラインから監視デバイスを削除し、パイプラインの最後の修正時間を計算することです。例えば、

(
process1 &
pid=$!
old=0
while   new=$(stat -L /dev/stderr -c %Y)
        [ $new != $old ]
do      old=$new
        sleep 60
done 3>&2 2>&1 1>&3   &&   kill -hup $pid
) |
process2

これにより、process1がバックグラウンドに配置されてpidを取得し、最後の修正時刻に対して出力パイプをポーリングできます。 60秒以内に変更がない場合は、PIDを終了できます。出力をキャプチャできるように、statファイル記述子1(つまりパイプ)をstderrとstatに置き換えます。

関連情報