0

我无计可施。我当前(失败)的小型 MySQL 支持网页的实现很大程度上依赖于一个模块 Project::Connection,该模块存储两个包范围(我们的)句柄(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;

项目.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;

项目/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>
4

1 回答 1

0

这对我也有用。我在这里使用了一个轻微的变体。$mysql_handle每当连接对象 ( ) 为空时,我都会尝试在处理程序中创建连接。这导致在第一个请求期间创建连接,并在孩子的一生中被缓存。

我不明白为什么在子初始化期间初始化的对象在响应阶段未定义,但这种解决方法似乎对我有用。

简而言之,我的工作就像以下

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

这在孩子的一生中按预期创建并缓存了一个连接。

于 2011-09-20T02:14:30.320 回答