Perl: поймать ошибку без кубика - PullRequest
8 голосов
/ 13 апреля 2010

Я поигрался с обработкой ошибок и получил небольшую проблему. Я соединяюсь с базой данных, используя модуль DBI.

Я делаю свою собственную обработку ошибок, используя подпрограмму, которую я вызываю при ошибке.

Я могу ловить свои матрицы и обрабатывать их просто отлично, но когда соединение с базой данных не удается, модуль DBI, по-видимому, выводит свой собственный кристалл:

Не удалось подключиться к DBI (...): ORA-12154: TNS: не удалось разрешить указанный идентификатор соединения (DBD ERROR: OCIServerAttach) в ...

Как бы я поймал это?

Я пытался использовать $SIG{__DIE__} примерно так:

local $SIG{__DIE__} = sub {
  my $e = shift;
  print "Error: " .$e;
};

Это внизу моего основного файла, в этом файле я также вызываю подпрограмму подключения, которая доступна в моем собственном модуле. Я также попытался поместить этот кусок кода в нижней части моего модуля, но он все еще печатает ошибку без

Ошибка:

перед ним.

Ответы [ 5 ]

8 голосов
/ 14 апреля 2010

Ошибка подключения DBI (...): ORA-12154: TNS: не удалось разрешить соединение указанный идентификатор (DBD ERROR: OCIServerAttach) в ...

Как бы я поймал это?

Чтобы поймать и обработать этот уровень ошибки, используйте eval в блочной форме "eval {...}". Это поймает любой кубик, который происходит в подкоде. Если код внутри блока eval умрет, он установит $ @, и блок вернет false. Если код не умирает, $ @ будет установлен в ''.

Использование обработки сигналов через SIG {WARN} и SIG {DIE} проблематично, поскольку они глобальны, также необходимо учитывать условия гонки (что произойдет, если я получу сигнал во время обработки другого сигнала? И т. Д.) традиционные проблемы обработки сигналов на основе). Вы, вероятно, пишете однопоточный код, поэтому вас не волнуют проблемы параллелизма нескольких вещей, вызывающих die, но есть пользователь, который нужно учитывать (возможно, он отправит SIGKILL, когда вы пытаетесь открыть соединение DBI )

В этом конкретном случае вы используете DBI. С помощью DBI вы можете контролировать то, что происходит в случае ошибки, если она молча умирает, предупреждает или терпит неудачу и ждет, пока вы проверите состояние возврата.

Вот базовый пример использования eval {...}.

my $dbh = eval { DBI->connect( @args) };
if ( $@ )
{
    #DBI->connect threw an error via die
    if ($@ =~ m/ORA-12154/i )
    {
        #handle this error, so I can clean up and continue
    }
    elsif ( $@ =~ m/SOME \s* other \s* ERROR \s+ string/ix )
    {
       #I can't handle this error, but I can translate it
        die "our internal error code #7";
    }
    else 
    {
      die $@; #re-throw the die
    }
}

Есть некоторые незначительные проблемы с использованием eval таким образом, связанные с глобальной областью действия $ @. Страница Try :: Tiny cpan имеет отличное объяснение. Try :: Tiny выполняет минимальную настройку блока Try / catch и обрабатывает локализацию $ @ и обработку других крайних случаев.

3 голосов
/ 14 апреля 2010

Включите это в ваш SIG{__DIE__} блок:

### Check if exceptions being caught.
return if $^S;

Это предотвратит использование вашего обработчика в коде на основе исключений, который генерирует кристалл в блоке eval.

3 голосов
/ 13 апреля 2010

Хорошо, нашел решение, по-видимому, мне нужно было __WARN__ вместо __DIE__, и этот фрагмент кода должен был находиться в верхней части файла, до того, как была выдана ошибка, в отличие от примера, который я прочитал выше :)

2 голосов
/ 13 апреля 2010

В DBI есть много переключателей, таких как PrintError, RaiseError и т. Д., Которые вы можете настроить. Смотри http://search.cpan.org/perldoc?DBI

0 голосов
/ 13 апреля 2010

Это не так универсально, как общий улавливатель кристаллов, но специально для обработки ошибок DBI у нас фактически есть наш собственный модуль, обеспечивающий обертки вокруг вызовов базы данных; и одна из функциональных возможностей модуля заключается в обтекании eval (в зависимости от флага) вокруг каждого вызова DBI.

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

...