2010-03-31 6 views
0

У меня проблема, когда я использую Apache :: DBI в дочерних процессах. Проблема заключается в том, что Apache :: DBI обеспечивает единый дескриптор для всех процессов, которые используют его, так что я получаюЧто такое безопасный способ использования fork с Apache :: DBI в mod_perl2?

DBD :: MySQL :: дб selectall_arrayref не удалось: команды из синхронизации; Вы не можете запустить эту команду теперь в /usr/local/www/apache22/data/test-fork.cgi линии 20.

Reconnection не помогает, так как Apache :: DBI воссоединяется в все процессы, как я понял следующее сообщение об ошибке

сервер обнаружил внутреннюю ошибку и не смог завершить свой запрос.

Сообщение об ошибке: драйвер DBD не имеет реализован AutoCommit атрибут в /usr/local/lib/perl5/site_perl/5.8.9/Apache/DBI.pm линии 283.,

Вот код происхождения:

use Data::Dumper 'Dumper'; 
use DBI(); 

my $dbh = DBI->connect($dsn, $username, $password, { 
     RaiseError => 1, 
     PrintError => 0, 
    }); 
my $file = "/tmp/test-fork.tmp"; 

my $pid = fork; 
defined $pid or die "fork: $!"; 

if ($pid) { 
    my $rows = eval { $dbh->selectall_arrayref('SELECT SLEEP(1)') }; 

    print "Content-Type: text/plain\n\n"; 
    print $rows ? "parent: " . Dumper($rows) : [email protected]; 
} 
else { 
    my $rows = eval { $dbh->selectall_arrayref('SELECT SLEEP(1)') }; 

    open FH, '>', $file or die "$file: $!"; 
    print FH $rows ? "child: " . Dumper($rows) : [email protected]; 
    close FH; 
} 

код я использовал для повторного соединения:

... 
else { 
    $dbh->disconnect; 
    $dbh = DBI->connect($dsn, $username, $password, $attrs); 
    my $rows = eval { $dbh->selectall_arrayref('SELECT SLEEP(1)') }; 

    open FH, '>', $file or die "$file: $!"; 
    print FH $rows ? "child: " . Dumper($rows) : [email protected]; 
    close FH; 
} 

Есть ли безопасный способ использования Apache :: DBI с forking? Есть ли способ заставить его создать новое соединение, возможно?

ответ

1

Я вижу несколько вариантов:

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

.: например

my $dbh = DBI->connect(...); 

my $pid = fork; 
defined $pid or die "fork: $!"; 

if ($pid) { 
    # parent... 
} 
else { 
    # child... 
    undef $dbh; 

Это может быть облегчено путем сохранения $dbh в объекте, и проходя вокруг этого объекта по мере необходимости для частей системы. Объект будет отвечать за повторное открытие $ dbh по мере необходимости, поэтому остальная часть приложения не должна заботиться о деталях. Держите код инкапсулированным и хорошо отделенным от других частей системы.

Я использую DBIx :: Connector в своей системе внутри объекта Moose, который использует делегацию метода для предоставления dbh. Приложение просто выполняет:

my $dbh = $db_dbj->dbh; 
my $sth = $dbh->prepare(...); 
# more boring DBI code here 

... И dbh повторно подключается/восстанавливается по мере необходимости, невидимо.


В стороне, вы должны быть очень осторожны с использованием голых дескрипторов файлов в многопроцессорной среде. Вы можете легко сбивать ваши данные. open (my $fh, $file) or die "Cannot open $file: $!" намного безопаснее.

Я также немного нервничаю, наблюдая, что вы используете eval {} блоков без проверки содержания [email protected]. Вы просто маскируете ошибки, а не имеете дело с ними, поэтому может быть больше вещей, чем вы знаете. Проверьте значение результата (или лучше использовать явный модуль обработки исключений, такой, как Try::Tiny. Использовать use strict; use warnings;.

PS. Я просто заметил, что вы явно включая DBI в вашем коде. Не делайте этого. Если вы используйте Apache :: DBI в вашем startup_modperl.pl (или как вы называете ваш файл начальной загрузки), вам никогда не придется включать сам DBI. Я не могу сказать точно, но я не уверен, что правильный пакет будет вызван (это было время, так как я смотрел на кишках Apache :: DBI в, он может позаботиться об этом за вас, хотя)

+0

Ваш первый вариант не подходит для меня. Ты это пробовал? – codeholic

+0

@codeholic: что вы подразумеваете под этим не работает? Вам придется снова вызвать '$ dbh = DBI-> connect (...)', так как $ dbh теперь не определено. – Ether

+0

@codeholic: ладно, я думаю, что все в моем ответе - это красная селедка - похоже, у вас что-то еще происходит. то есть «что-то» передает атрибут AutoCommit ненадлежащим образом. Является ли эта проблема чем-то новым, что только что началось, или у вас всегда было это? Я подозреваю, что в ваших конфигах происходит что-то странное. – Ether

 Смежные вопросы

  • Нет связанных вопросов^_^