Помогите устранить ошибку, которая постоянно повторяется в 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);
}
Это дает поведение А.