perlforkdbimod-perl2apache-dbi

What is the safe way to use fork with Apache::DBI under mod_perl2?


I have a problem when I use Apache::DBI in child processes. The problem is that Apache::DBI provides a single handle for all processes which use it, so I get

DBD::mysql::db selectall_arrayref failed: Commands out of sync; you can't run this command now at /usr/local/www/apache22/data/test-fork.cgi line 20.

Reconnection doesn't help, since Apache::DBI reconnects in all processes, as I understood the following error

The server encountered an internal error and was unable to complete your request.

Error message: DBD driver has not implemented the AutoCommit attribute at /usr/local/lib/perl5/site_perl/5.8.9/Apache/DBI.pm line 283. ,

Here's the origin code:

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) : $@;
}
else {
    my $rows = eval { $dbh->selectall_arrayref('SELECT SLEEP(1)') };

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

The code I used for reconnection:

...
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) : $@;
    close FH;
}

Is there a safe way to use Apache::DBI with forking? Is there a way to make it create a new connection perhaps?


Solution

  • Don't fork under mod_perl2. Use Apache2::Subprocess. See also Is it a bad idea to fork under mod_perl2?