Помогите устранить ошибку, которая постоянно повторяется в mod_perl2 / $SIG{__DIE__}

Это mod_perl2 в Apache 2.2, ActiveState Perl 5.10 для win32.

Я переопределяю $SIG{__DIE__} и включите флаг RaiseError DBI, который 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} назначен (поведение А). Еще незнакомец, могу поставить {allowed} к любому набору чисел, и, пока он содержит, в частности, "22007", я получаю поведение B. Если это не так, я получаю поведение C. Еще более странно, я могу фактически заполнить свое переопределение чем угодно (предупреждениями, вызовами в CORE::dieи т. д.- до тех пор, пока он компилируется), и я по-прежнему получаю поведение B - даже если переопределение больше не содержит кода, который сделал бы это возможным! Также я не получаю ожидаемых результатов звонков warn а также CORE::dieпросто молчание в журналах, поэтому я даже не могу попытаться вручную отследить путь выполнения через мое переопределение.

Я перезапускал Apache2.2 между каждым сохранением скрипта. Я даже переместил переопределение в тот же файл скрипта, что и сам скрипт, из модуля, где он обычно находится, и закомментировал весь файл модуля, где обычно переопределение, и перезапустил.

Если я уберу эту первую строчку или выберу из нее '22007', я смогу warn а также die а в остальном вручную отлаживаю все что мне нравится, и все работает как положено. Что такое "22007", что он никогда не выводит ничего другого, несмотря на перезагрузку сервера? Нет ссылок на "22007" где-либо еще во всем проекте, кроме карты перевода, и я могу полностью удалить ее из этого файла и перезапустить, и результат ничем не отличается. Он ведёт себя так, как если бы он кешировал мое переопределение ранее в тот же день и никогда не забудет. Это не проблема кеша браузера, потому что я могу добавить случайные строки запроса, и результаты ничем не отличаются.

Это самый странный и самый расстраивающий опыт mod_perl2, который у меня когда-либо был, и у меня закончились идеи. У кого-нибудь есть намеки? Единственное, о чем я могу думать - это проблема с кэшированием, но я перезапускал сервис бесчисленное количество раз.

Так как это был конец дня, я подумал, что попытаюсь полностью перезагрузить серверный компьютер, и это все равно ничего не изменило. Я даже перед перезапуском сервера изменил единственную строку где {state} назначен на это:

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

И все же, выход потом был {test} как "22007", что должно быть, только если я ушел = $errno неповрежденными.

Даже если это был, скажем, обратный прокси-сервер, который проходит через кэширование, эта ситуация не имеет смысла для меня, поскольку запрос может быть другим. После полного перезапуска сервера, как он может по-прежнему присваивать значение, которого больше нет в коде, то есть, как он может использовать мой старый $SIG{__DIE__} переопределить после полного перезапуска, когда он больше не существует ни в одном файле?

Обновление: я также попытался изменить допустимые ошибки на "42601" и изменить вызов d b на 'select', который выдает этот код ошибки, но не добавляет его в карту перевода. Это все еще дает мне поведение B, настройка {state} на "42601", так что это не относится к "22007". Любой код ошибки, который вставлен в {allowed}Если эта ошибка действительно происходит, он запускает старую версию переопределения. Вызвать ошибку, которой нет в {allowed} и он запускает текущую версию. Но как он узнает, находится ли текущая ошибка в {allowed}или что это вообще что-то значит, прежде чем перейти к переопределению? (Потому что переопределение является единственным местом, где {allowed} grep для текущей ошибки.)

1 ответ

Решение

Это мой временный обходной путь, но я бы хотел разгадать тайну и не нужно добавлять лишнюю строку везде, где у меня есть вызов БД с допустимыми ошибками.

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);
}

Это дает поведение А.

Другие вопросы по тегам