2

コマンドファイルを読み取り、必要に応じて再起動する Perl スクリプトがあります。

myscript.pl:

exec '/home/foo/bin/myscript.pl';
exit(0);

これで、1 つの問題を除いて問題なく動作します。コマンド ファイルを読み取るスレッドは、私が使用する DBI ハンドルにアクセスできません。そして、何度も再起動すると、恐ろしい「接続が多すぎます」というエラーが発生するまで、開いているmysql接続の数が増えているようです。DBI仕様は次のように述べています:

「この(おそらく一時的な)制限のため、新しく作成されたスレッドはデータベースへの独自の接続を確立する必要があります。ハンドルはスレッド間で共有できません。」

接続を閉じる方法、またはスクリプトを再起動する別の方法はありますか?

4

3 に答える 3

2

スレッド間で共有されるフラグ変数を使用します。コマンドライン読み取りスレッドにフラグを設定して終了させ、DB ハンドルを保持しているスレッドにそれを解放させ、実際に再実行を実行させます。

#!/usr/bin/perl

use threads;
use threads::shared;

use strict; use warnings;
my $EXIT_FLAG :shared;

my $db_thread = threads->create('do_the_db_thing');
$db_thread->detach;

while ( 1 ) {
    sleep rand 10;
    $EXIT_FLAG = 1 if 0.05 > rand or time - $^T > 20;
}

sub do_the_db_thing {
    until ( $EXIT_FLAG ) {
        warn sprintf "%d: Working with the db\n", time - $^T;
        sleep rand 5;
    }
    # $dbh->disconnect; # here
    warn "Exit flag is set ... restarting\n";
    exec 'j.pl';
}
于 2009-12-02T21:06:15.400 に答える
2

atexit 関数を登録して、DBI ハンドルが開かれた時点で閉じてから、exec ではなく fork & exec を使用してスクリプトを再起動することができます。次に、親は exit を呼び出し、atexit コールバックを呼び出して DBI ハンドルを閉じます。子は正常に再実行できました。

編集:さらに数分間考えた後、親の終了時にハンドルが自動的に閉じられるため、atexit を完全にスキップできると思います。もちろん、DB ハンドルを閉じるときに、単純なファイルハンドルを閉じるよりも複雑な操作を行う必要がある場合を除きます。

my $pid = fork();
if (not defined $pid) {
    #Could not fork, so handle the error somehow
} elsif ($pid == 0) {
    #Child re-execs itself
    exec '/home/foo/bin/myscript.pl';
} else {
    #Parent exits
    exit(0);
}
于 2009-12-02T21:09:56.737 に答える
2

多くの接続が予想される場合は、DBI::Goferを DBI プロキシとして機能させたいと思うでしょう。あなたは好きなだけ多くのスクリプトで接続を作成し、DBI::Gofer は可能なときにそれらを共有します。

于 2009-12-02T23:02:58.657 に答える