Как мне создать постоянный дескриптор соединения (для MySQL и memcached) в mod_perl2 для каждого дочернего процесса Apache2? - PullRequest
0 голосов
/ 24 августа 2011

Я нахожусь в конце моего остроумия.Моя текущая (неудачная) реализация небольшой веб-страницы, поддерживаемой MySQL, в значительной степени опирается на модуль Project :: Connection, в котором хранятся два дескриптора области пакета (our'd) (mysql_handle и memc_handle), которые инициализируются вызовом Project :: Connection:: child_init на этапе PerlChildInitHandler.Точно так же я (хочу) отключить соединения во время фазы PerlChildExitHandler.Проблема в том, что моя отладка подтвердила, что обработчики правильно созданы во время подпрограммы ChildInit, но когда я запрашиваю «GET /», модуль, обрабатывающий запрос (Project :: Web :: Home, который использует Project :: Connection), сообщаетчто оба дескриптора не определены!

Вот соответствующий код:

startup.pl (вызывается с помощью PerlRequire в конфигурации сервера):

use Apache2::Reload; # PerlInitHandler inside /var/www
use Apache2::ServerUtil;

use lib "/var/www/app";
use Project; # has the response handler
use Project::Connection; # has  the childinit and childexit handlers

$s = Apache2::ServerUtil->server;
$s->set_handlers('PerlChildInitHandler' => \&Project::Connection::child_init);
$s->set_handlers('PerlChildExitHandler' => \&Project::Connection::child_exit);

1;

Project / Connection.pm(содержит дескрипторы соединения):

package Project::Connection;

use DBI;
use Cache::Memcached;
use Project::Config;

our ($mysql_handle, $memc_handle);

sub mysql { $mysql_handle }
sub memc  { $memc_handle  }

sub child_init {

    # create the mysql connection
    my ($db, $host, $port, $user, $pass)
        = Project::Config::get('db', 'db_host', 'db_port', 'db_user', 'db_pass');
    $mysql_handle = DBI->connect("dbi:mysql:database=$db;host=$host;port=$port",
                                  $user, $pass)
        or die "Failed to establish a connection with mysqld: $DBI::errstr";

    # create the memcache connection
    my ($socket) = Project::Config::get('memcached_sock');
    $memc_handle = Cache::Memcached->new('servers' => $socket)
        or die "Failed to establish a connection with memcached";
}

sub child_exit {
    $mysql_handle->disconnect;
    $memc_handle->disconnect_all;
}

1;

Project.pm:

package Project;

use Apache2::Const;
use Apache2::Request;

use Project::Web::Home;

sub handler {
    my ($request_rec) = @_;
    my $request = Apache2::Request->new( $request_rec );

    # load the module for the webpage
    my $page = substr $request->uri, 1;
    $page = length $page ? 'home' : $page; # take care of directory requests
    eval "Project::Web::${page}::do";
    if ($@) {
        Project::Web::home::do; # do this rather than 404
    }

    Apache2::Const::OK;
}

1;

Project / Web / home.pm:

package Project::Web::home;

use strict;
use warnings;

use Project::Connection;

sub do {
    my ($user, $args) = @_;
    print "Content-Type: text/plain\n\n";
    $dbh = Project::Connection::mysql; # this is undefined!

    # ...
}

1;

Теперь этоНасколько я понимаю, во время запуска Apache, когда он компилирует и запускает startup.pl, все модули компилируются в родительский процесс.Затем родительский процесс разветвляется на дочерние процессы, копируя скомпилированный код, так что дочерний процесс становится копией родительского.После этого дочернему процессу СЛЕДУЕТ запустить Project :: Connection :: child_init, который инициализирует дескрипторы для mysql и memcache, так что когда дочерний элемент обрабатывает «GET /», модуль Project :: Web :: home может «использовать Project :: Connection»«чтобы получить эти ручки;и, наконец, эти дескрипторы должны оставаться определенными для всего процесса потомка.

Разделение дополнительной информации, которую вы, возможно, захотите узнать:

Из журнала: "Apache / 2.2.16 (Debian) mod_apreq2-20090110 / 2.7.1 mod_perl / 2.0.4 Perl / v5.10.1 настроен "из / etc / apache2 / sites-available / project:

<VirtualHost *:80>
    ServerAdmin admin@project.com
    ServerName project.com
    DocumentRoot "/var/www"
    PerlRequire "/var/www/bin/startup.pl"
    <Directory "/var/www/">
        SetHandler "perl-script"
        PerlInitHandler "Apache2::Reload"
        PerlResponseHandler "Project"
        PerlOptions -SetupEnv +ParseHeaders
        Options ExecCGI
        Order allow,deny
        Allow from all
    </Directory>
</VirtualHost>

1 Ответ

0 голосов
/ 20 сентября 2011

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

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

sub mysql { &child_init unless defined $mysql_handle; return $mysql_handle }

Это создало и кэшировало одно соединение, как и ожидалось на протяжении всей жизни ребенка.

...