代码之家  ›  专栏  ›  技术社区  ›  Kev

帮助解决一致可重复的mod perl2/$sig_uuu die bug

  •  0
  • Kev  · 技术社区  · 15 年前

    这是Apache 2.2上的mod_perl2,Win32的activestate perl 5.10。

    我超越 $SIG{__DIE__} 并打开DBI的raiseError标志,该标志远离文档,当数据库调用失败时应调用我的override。几乎总是这样,除了一种情况,我不明白为什么。

    我的剧本有一个 our $page 变量,作为mod euperl2,我可以从重写中得到这个,比如:

    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 ,我有一个数组引用“allowed”错误值,当它们从数据库返回时,我想对它们做一些不同的事情。当数据库抛出其中一个错误时,我想将其转换为用户友好的消息, $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_ 重写,它工作:JSON响应在重写、打印和执行之前停止 {test} 分配(行为A)。还是个陌生人,我可以 {allowed} 对于任何一组数字,只要它特别包含“22007”,我就得到行为B。如果它不包含行为C,则得到行为C。更奇怪的是,我实际上可以用任何内容(警告、调用 CORE::die 等等,只要它编译,我仍然得到行为b——即使覆盖不再包含任何使其成为可能的代码!另外,我也没有收到 warn 核心:模具 ,只是在日志中保持沉默,所以我甚至无法尝试通过重写手动跟踪执行路径。

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

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

    这是我所经历过的最奇怪和最令人沮丧的mod perl2体验,我已经没有想法了。有人有什么提示吗?我唯一能想到的是,这是一个缓存问题,但我已经多次重新启动了该服务。

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

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

    然而,后来的产出 {测试} 作为“22007”,只有我离开了才应该是这样 = $errno 完整的。

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

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

    1 回复  |  直到 15 年前
        1
  •  0
  •   Kev    15 年前

    这是我的临时解决方案,但我想解决这个问题,不必在任何有允许错误的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。