Это 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}
(поведение A). Тем не менее, я могу установить {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' и изменить вызов db на 'select'
, который генерирует этот код ошибки, но не добавляет его в карту перевода. Это все еще дает мне поведение B, устанавливая {state}
в '42601', так что это не специфично для '22007'. Любой код ошибки, который вставляется в {allowed}
, если эта ошибка действительно происходит, он использует старую версию переопределения. Вызвать ошибку, которой нет в {allowed}
, и она запускает текущую версию. Но как узнать, находится ли текущая ошибка в {allowed}
или что это вообще что-то значит, прежде чем перейти к переопределению? (Поскольку переопределение является единственным местом, где {allowed}
отображается для текущей ошибки.)