0

Heroku ログを追跡する管理スクリプトを作成し、n 秒ごとに平均を要約して、特定のしきい値を超えた場合に通知します (はい、私は知っていて、新しい遺物が大好きですが、カスタムを行いたいです)。

これがスクリプト全体です。

私は IO とスレッドのマスターになったことはありません。愚かな間違いを犯しているのだろうかと思います。while(true){}犯人である可能性のあるデーモンスレッドがいくつかあります。例えば:

# read new lines
f = File.open(file, "r")
f.seek(0, IO::SEEK_END)
while true do
  select([f])
  line = f.gets
  parse_heroku_line(line)
end

1 つのデーモンを使用してログの新しい行を監視し、もう 1 つのデーモンを定期的に要約します。

誰かがプロセッサの負荷を軽減する方法を見ていますか?

4

2 に答える 2

6

一時ファイルからの読み取り中に実際にブロックすることはないため、これはおそらく熱くなります。POSIX select(2)IO::select上の薄いレイヤーです。ファイルの読み取り準備が整うまでブロックしようとしているように見えますが、select(2) は EOF が準備完了 (「ファイル記述子もファイルの終わりで準備完了」) であると見なすため、常にすぐに戻ります。 from select then call gets は EOF で nil を返します。

一時ファイルに書き込むスレッドを回避し、代わりに使用IO::popenしてログテーラーをフォークし、%x[heroku logs --ps router --tail --app pipewave-cedar]ループオーバーできる ruby​​ IO オブジェクトに接続して、返されgetsたときに終了する(ログを示す仕立て屋完成)。テーラーからのパイプでは、読み取るものが何もないときにブロックされ、スクリプトは行の解析とレポートを実行するのに必要なだけ実行されます。getsnilgets

編集:実際にコードを試すように設定されていませんが、ログテーラースレッドと一時ファイルの読み取りループをこのコードに置き換えて、上記の動作を取得できるはずです:

IO.popen( %w{ heroku logs --ps router --tail --app my-heroku-app } ) do |logf|
  while line = logf.gets
    parse_heroku_line(line) if line =~ /^/
  end
end

@total_linesまた、レポート スレッドが、などへのアクセスを同期するために何もしていないことに気付きました@total_errors。そのため、メソッドが更新されるインスタンス変数から一貫性のない値を取得できるマイナーな競合状態がいくつかありparse_heroku_lineます。

于 2012-07-06T19:01:49.287 に答える
1

select読み取りがブロックされるかどうかについてです。f は単純な古いファイルなので、読み取りが最後に到達してもブロックされず、即座に nil が返されます。その結果select、期待どおりに何かがファイルに追加されるのを待つのではなく、すぐに返されます。このため、タイトなビジー ループに座っているため、CPU の使用率が高くなることが予想されます。

あなたがeofにいる場合(チェックするか、nilを返すf.eof?かどうかを確認できgetsます)、スリープを開始するか(おそらく何らかのバックオフを使用して)、リッスンなどを使用してファイルシステムの変更の通知を受け取ることができます

于 2012-07-06T18:52:21.757 に答える