4

AnyEvent を使用して頻繁にファイルに書き出すスクリプトがあります。私が直面している問題を説明するために、次のサンプルを作成しました。

#!/usr/bin/perl

use strict;
use warnings;

use AnyEvent;
use AnyEvent::Handle;

my $outputFile = 'out_test.log';
open my $out, ">>", $outputFile or die "Can't open output\n";

my $data = "test string"x50000 . "\n";

my $out_ready = AnyEvent->condvar;
my $out_hdl; $out_hdl = AnyEvent::Handle->new(
    fh => $out,
    on_error => sub {
        my ($hdl, $fatal, $msg) = @_;
        AE::log error => $msg;
        $hdl->destroy;
        $out_ready->send;
    }
);

my $timer = AnyEvent->timer(
    after => 0,
    interval => 5,
    cb => sub {
        $out_hdl->push_write($data);
    }
);

$out_ready->recv;

これはうまく機能しますが、しばらくするとファイル サイズが膨大になります。このような問題には logrotate を使用するため、次の logrotate 構成ファイルを作成しました。

/path/to/out_test.log {
        size 2M
        copytruncate
        rotate 4
}

これもうまく機能し、上記の出力ファイルが 2M を超えるたびに、out_test.log.1 にローテーションされます。ただし、ローテーション直後に out_test.log を書き込むと、ファイルサイズはローテーションしたログファイルと同じになります。この動作と私が経験していることは、https ://serverfault.com/a/221343 で説明されています。

問題は理解できましたが、提供したサンプル Perl コードの問題を修正する方法がわかりません。

logrotate を使用してログ ローテーションを実装する必要はありませんが、実装することをお勧めします。スクリプトに実装するのが簡単であればそれもできますが、上記のサンプルを logrotate でうまく動作させることができればいいと思います。ヘルプやコメントをいただければ幸いです。ありがとう!

編集

以下の回答に基づいて、提供されたmonkeypatch ikegamiで物事を機能させることができ、Marc Lehmannのアドバイスに従ってネイティブperl I / Oを活用することができました。私のコード例は次のようになり、うまく機能します。さらに、これにより、logrotate の copytruncate ディレクティブの要件が削除されます。

#!/usr/bin/perl

use strict;
use warnings;

use AnyEvent;
use AnyEvent::Handle;

my $outputFile = 'out_test.log';
open my $out, ">>", $outputFile or die "Can't open output\n";

my $data = "test string"x50000 . "\n";

my $cv = AnyEvent::condvar();
my $timer = AnyEvent->timer(
    after => 0,
    interval => 5,
    cb => sub {
        open my $out, ">>", $outputFile or die "Can't open output\n";
        print $out $data;
        close $out; 
    }
);

$cv->recv;
4

2 に答える 2

2

ikegamis の回答は非常に誤解を招くものです。コードにはバグが含まれています。つまり、ファイル I/O に AnyEvent::Handle を使用しています。これは文書化されておらず、サポートされていない動作です。池上が認識している「バグ」は、不正なファイル ハンドルで AnyEvent::Handle を使用した結果です。

文書化されていない動作やモンキーパッチに頼って魔法のように機能することを期待することはできますが、ストリーム以外のファイルハンドルに AnyEvent::Handle を使用している限り、問題が発生し続ける可能性が高いため、実際のバグを修正することをお勧めします。

イベントベースのファイル I/O を行いたい場合は、AnyEvent::IO を調べる必要があります (そして、IO::AIO などの適切なバックエンドをインストールします)。それ以外の場合は、通常の perl I/O 関数 (組み込み、IO:: クラスなど) を使用してファイルにアクセスする必要があります。

更新: AnyEvent::Handle がファイルで機能しないより深い理由は、非ブロッキング I/O の概念が有用な方法でファイルに適用されないため、最終的には意味をなさないため、AnyEvent:: を使用することです。ハンドルはオーバーヘッドを追加するだけです。

于 2015-06-28T09:26:59.460 に答える