0

这是 Apache 2.2 上的 mod_perl2,win32 上的 ActiveState Perl 5.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,我有一个“允许”错误值的数组引用,当它们从数据库返回时,我想做一些不同的事情。当数据库抛出这些错误之一时,我想将其转换为用户友好的消息,$r->print即 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——即使覆盖不再包含任何使其成为可能的代码!此外,我没有得到对warnand的调用的任何预期结果CORE::die,只是在日志中保持沉默,所以我什至无法尝试通过我的覆盖手动跟踪执行路径。

我在每个脚本保存之间重新启动了 Apache2.2。我什至将覆盖移到与脚本本身相同的脚本文件中,移出它通常所在的模块,并注释掉覆盖通常所在的整个模块文件,然后重新启动。

如果我取出第一行,或者从中取出“22007”,我可以warn手动die调试我喜欢的所有内容,并且一切都按预期工作。尽管服务器重置,它从不输出任何不同的“22007”是什么?除了翻译图,整个项目的其他任何地方都没有对“22007”的引用,我可以将它从该文件中完全删除并重新启动,结果没有什么不同。它的行为就好像它已经缓存了我当天早些时候的覆盖并且永远不会忘记。这也不是浏览器缓存问题,因为我可以添加随机查询字符串,结果没有什么不同。

这是我有过的最奇怪和最令人沮丧的 mod_perl2 体验,而且我已经没有想法了。有人有任何提示吗?我唯一能想到的是这是一个缓存问题,但我已经无数次重启了服务。

由于这是一天的结束,我想我会尝试完全重新启动服务器计算机,但它仍然没有改变任何东西。{state}我什至在重新启动服务器之前更改了分配给它的唯一行:

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

然而,之后的输出为“22007”,只有在我完好无损{test}的情况下才应该是这样。= $errno

即使它是进行缓存的反向代理,这种情况对我来说也没有意义,因为请求可能不同。在完全重新启动服务器后,它如何仍然分配一个不再存在于代码中的值,即$SIG{__DIE__},当它不再存在于任何文件中时,它如何在完全重新启动后使用我的旧覆盖?

更新: 我还尝试将允许的错误更改为 '42601' 并将 db 调用更改为'select',这会产生该错误代码,但没有将其添加到翻译映射中。它仍然给我行为 B,设置{state}为“42601”,所以它不是特定于“22007”。放入的任何错误代码{allowed},如果确实发生了该错误,则它正在运行旧版本的覆盖。导致不存在的错误,{allowed}它运行当前版本。但是,在覆盖之前,它如何知道当前错误是否在 中{allowed},或者这是否意味着什么?{allowed}(因为覆盖是当前错误的唯一位置。)

4

1 回答 1

0

这是我的临时解决方法,但我想解开谜团,而不必在我有允许错误的数据库调用的任何地方添加额外的行。

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 回答