开发者

How do I create a persistent connection handle (for MySQL and memcached) under mod_perl2 for each child process of Apache2?

I'm at my wit's end. My current (failed) implementation of small MySQL-backed webpage heavily relies on a module Project::Connection that stores two package-scoped (our'd) handles (mysql_handle and memc_handle) that are initialized with a call to Project::Connection::child_init during the PerlChildInitHandler phase. Similarly, I (want to) disconnect the connections during the PerlChildExitHandler phase. The problem is that my debugging confirmed that the handlers are properly created during the ChildInit subroutine, but when I request "GET /", the module that handles the request (Project::Web::Home, which use's Project::Connection) reports that both handles are undefined!

Here's the relevant code:

startup.pl (called with PerlRequire in the server configuration):

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 (holds the connection handles):

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;

Now, it is my understanding that during Apache's startup, when it compiles and runs startup.pl, all modules are compiled into the parent process. Then the parent process forks into child processes, copying the compiled code so that the child becomes a copy of the parent. After that, the child process SHOULD run Project::Connection::child_init which initializes the handles for mysql and memcache so that when the child handles "GET /", the Project::Web::home module can "use Project::Connection" to get those handles; and, finally, that those handles should remain defined for the entirety of the child's process.

Parting extra information you might want to know:

From the log: "Apache/2.2.16 (Debian) mod_apreq2-20090110/2.7.1 mod_perl/2.0.4 Perl/v5.10.1 configured" From /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>


This dint work for me as well. I used a slight variant here. I tried to create a connection in the handler whenever the connection object ( $mysql_handle ) was empty. This resulted in the creation of connection during the first request and it was cached throughout the child's life.

I could not see why the object initialized during the child init gets undefined during the response phase but this work around seemed to work for me.

In short my work around was like following

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

This created and cached one connection as expected through out the child's life.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜