0

これは、Apache 2.2ではmod_perl2、win32ではActiveStatePerl5.10です。

$SIG{__DIE__}DBIのRaiseErrorフラグをオーバーライドしてオンにします。これは、データベース呼び出しが失敗したときに、ドキュメントのAFAICTがオーバーライドを呼び出す必要があります。ある場合を除いて、ほとんどの場合そうですが、その理由がわかりません。

私のスクリプトにはour $page変数があり、mod_perl2であるため、次のようにオーバーライドからこれを取得できます。

use Carp::Trace;
my $full_trace = Carp::Trace::trace;
$full_trace =~ m/^(ModPerl::ROOT::ModPerl::Registry::.*::)handler .*$/m;
my $page;
if (defined $1)
{
    eval '$page = $' . $1 . 'page';
    if (defined $page)
    {
        $json = 1 if defined $$page{json_response};
        if (defined $$page{dbh})
        {
            my $errno = $$page{dbh}->state;
            if ($errno ~~ $$page{error_handling}{allowed})
            {
                # allowed to let it go--no report, expected possible user error at some level that couldn't be caught sooner (usually db level)
                my $errmsg = $$page{error_handling}{translation_map}{$errno};
                if (defined $errmsg)
                                    {
                                               ...

これは正常に機能します。さて、その中$pageに、DBから戻ってきたときに何か別のことをしたい「許可された」エラー値の配列参照があります。$r->printDBがこれらのエラーの1つをスローした場合、それをJSONのユーザーフレンドリーなメッセージに変換し、実行を停止します(動作A)。何らかの理由で、代わりにスクリプトに制御を戻します(動作B)。

これが私のスクリプトの主要部分です:

{
    $$page{error_handling}{allowed} = ['22007'];
    $$page{json_response}{result} = $page->one_liner("select 'aa'::timestamp");
    $$page{json_response}{test} = $$page{error_handling}{state};
}
    $page->make_json; # just JSONifies $$page{json_response} and prints it

最初の行をコメントアウトすると、通常のエラー(予期しない処理)(動作C)が発生します。これは、発生しているエラーを許可されたエラーのリストに追加していないためです。本当に奇妙なのは、その最初の行を切り取って$SIG{__DIE__}オーバーライドに貼り付けると、それが機能することです。JSON応答がオーバーライドされ、出力され、{test}割り当てられる前に実行が停止します(動作A)。見知らぬ人でも、{allowed}任意の数値セットに設定できます。特に「22007」が含まれている限り、動作Bが発生します。含まれていない場合は、動作Cが発生します。さらに奇妙なことに、実際にオーバーライドを埋めることができます。何でも(警告、への呼び出しCORE::die、など-コンパイルする限り)そして私はまだ振る舞いBを取得します-オーバーライドにはそれを可能にするコードが含まれていなくても!warnまた、とへの呼び出しの期待される結果が得られずCORE::die、ログが沈黙しているだけなので、オーバーライドを介して実行パスを手動で追跡することさえできません。

スクリプトを保存するたびにApache2.2を再起動しました。オーバーライドをスクリプト自体と同じスクリプトファイルに移動し、通常のモジュールから外し、モジュールファイル全体をコメントアウトして、再起動しました。

その最初の行を削除するか、「22007」を削除するwarndie、好きなものをすべて手動でデバッグでき、すべてが期待どおりに機能します。サーバーがリセットされても何も出力されない「22007」についてはどうでしょうか。翻訳マップを除いて、プロジェクト全体のどこにも「22007」への参照はありません。そのファイルから完全に削除して再起動すると、結果に違いはありません。それはあたかもその日の早い段階から私のオーバーライドをキャッシュしたかのように振る舞い、決して忘れることはありません。ランダムなクエリ文字列を追加でき、結果も変わらないため、ブラウザのキャッシュの問題でもありません。

これは私が今までに経験した中で最も奇妙で最も苛立たしいmod_perl2の経験であり、私はアイデアを使い果たしました。誰かヒントはありますか?私が考えることができる唯一のことは、それがキャッシングの問題であるということです、それでも私はサービスを数え切れないほど再起動しました。

一日の終わりだったので、サーバーコンピュータを完全に再起動してみようと思いましたが、それでも何も変わりませんでした。サーバーを再起動する前に、{state}これに割り当てられている唯一の行を変更しました。

$$page{error_handling}{state} = 'my face'; # $errno;

それでも、その後の出力は{test}「22007」でした。これは、私がそのままにしておいた場合にのみあるはず= $errnoです。

たとえば、キャッシングを実行するリバースプロキシであったとしても、要求が異なる可能性があるため、この状況は私には意味がありません。サーバーを完全に再起動した後も、コードに存在しない値を割り当てるにはどうすればよいでしょうか。つまり、$SIG{__DIE__}完全に再起動した後、ファイルに存在しなくなった古いオーバーライドをどのように使用できるでしょうか。

更新: 許可されたエラーを「42601」に変更し、db呼び出しをに変更しようとしました'select'。これにより、そのエラーコードが生成されますが、変換マップには追加されませんでした。それでも動作Bが得られ、「42601」に設定{state}されているため、「22007」に固有のものではありません。に入れられたエラーコードは{allowed}、そのエラーが実際に発生した場合、古いバージョンのオーバーライドを実行しています。にないエラーが発生し{allowed}、現在のバージョンが実行されます。{allowed}しかし、オーバーライドに到達する前に、現在のエラーがにあるかどうか、またはそれが何かを意味するかどうかをどのように知るのでしょうか?{allowed}(オーバーライドは、現在のエラーに対してgrepさ​​れる唯一の場所であるためです。)

4

1 に答える 1

0

これは私の一時的な回避策ですが、謎を解き、許可されたエラーのあるDB呼び出しがあるすべての場所に余分な行を追加する必要はありません。

package MyModule::ErrorLogging;
sub InsanityWorkaround # duplicates part of $SIG{__DIE__} override for allowed errors
{
    my ($page) = @_;
    my $r = $$page{r};
    my $errno = $$page{error_handling}{state};
    if ($errno ~~ $$page{error_handling}{allowed})
    {
        # allowed to let it go--no report, expected possible user error at some level that couldn't be caught sooner (usually db level)
        my $errmsg = $$page{error_handling}{translation_map}{$errno};
        if (defined $errmsg)
        {
            use JSON::XS qw(encode_json);
            $$page{json_response} =
            {
                error => $errmsg,
            };
            my $response = encode_json($$page{json_response});
            $r->content_type("application/json");
            $r->print($response);
            exit(0);
        }
        else
        {
            return 0; # get back to script where {state} can be checked and output can be customized even further
        }
    }
    return;
}

次に、私のスクリプトは次のようになります。

{
    $$page{error_handling}{allowed} = ['22007']; # don't be bothered by invalid timestamp error
    $$page{json_response}{result} = $page->one_liner("select 'aa'::timestamp");
    MyModule::ErrorLogging::InsanityWorkaround($page);
}

これは行動Aを与えています。

于 2010-01-27T14:20:14.193 に答える