2010-03-31 7 views
0

J'ai un problème lorsque j'utilise Apache :: DBI dans les processus enfants. Le problème est que Apache :: DBI fournit une poignée unique pour tous les processus qui l'utilisent, donc je reçoisQuel est le moyen sûr d'utiliser fork avec Apache :: DBI sous mod_perl2?

DBD :: mysql :: db selectall_arrayref échoué: Commandes désynchronisés; vous ne pouvez pas exécuter cette commande maintenant à /usr/local/www/apache22/data/test-fork.cgi ligne 20.

Reconnexion ne fonctionne pas, car Apache :: DBI reconnecte en tous les processus, comme je l'ai compris l'erreur suivante

le serveur a rencontré une erreur interne et n'a pas pu terminer votre demande .

Message d'erreur: pilote DBD n'a pas mis en œuvre l'attribut AutoCommit à /usr/local/lib/perl5/site_perl/5.8.9/Apache/DBI.pm ligne 283.,

Voici le code d'origine:

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; 
} 

le code j'ai utilisé pour rebranchement:

... 
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; 
} 

Existe-t-il un moyen sûr d'utiliser Apache :: DBI avec forking? Y a-t-il un moyen de le faire créer une nouvelle connexion peut-être?

Répondre

1

Je vois quelques options:

  • Explicitement fermer votre DB poignées lorsque vous fourchette, et les ouvrez à nouveau au besoin.

.: par exemple

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

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

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

Cela pourrait être facilitée par le stockage du $dbh dans un objet, et en passant autour de cet objet au besoin pour les parties de votre système. L'objet serait responsable de rouvrir le $ dbh comme nécessaire, de sorte que le reste de l'application n'a pas à se préoccuper des détails. Gardez le code encapsulé et bien séparé des autres parties du système. Ne pas utiliser Apache::DBI. Je peux fortement recommander DBIx::Connector, qui ouvre une nouvelle connexion si nécessaire et ne conserve pas le mauvais comportement de plain DBI ou Apache :: DBI: voir http://search.cpan.org/~dwheeler/DBIx-Connector-0.32/lib/DBIx/Connector.pm#Description pour une description détaillée de la façon dont il diffère. J'utilise DBIx :: Connector dans mon système à l'intérieur d'un objet Moose qui utilise une délégation de méthode pour fournir le dbh. L'application fait simplement:

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

... Et le dbh est reconnecté/régénéré selon les besoins, de manière invisible.En outre, vous devriez faire très attention d'utiliser des handles de fichiers nus dans un environnement multiprocessus. Vous pourriez être très facilement en train de tabasser vos données. open (my $fh, $file) or die "Cannot open $file: $!" est beaucoup plus sûr.

Je suis aussi un peu nerveux en vous voyant utiliser eval {} blocs sans vérifier le contenu de [email protected]. Vous ne faites que masquer les erreurs, plutôt que de les traiter. Il se peut donc qu'il se passe plus de choses que vous ne le pensez. Vérifiez vos valeurs de résultat (ou mieux, utilisez un explicite module de gestion des exceptions, comme Try::Tiny. Utiliser use strict; use warnings;.

PS. Je viens de remarquer que vous incluez explicitement DBI dans votre code. Ne pas le faire. Si vous utilisez Apache :: DBI dans votre startup_modperl.pl (ou ce que vous appelez votre fichier bootstrap), vous ne devriez jamais avoir à inclure DBI lui-même, je ne peux pas le dire mais je ne serais pas sûr que le bon paquet soit appelé (il a été un moment que je regardais les tripes d'Apache :: DBI, il pourrait prendre soin de cela pour vous si)

+0

Votre première option ne fonctionne pas pour moi. L'as tu essayé? – codeholic

+0

@codeholic: qu'est-ce que vous voulez dire par ça ne marche pas? Vous devrez appeler à nouveau '$ dbh = DBI-> connect (...)' car le $ dbh est maintenant indéfini. – Ether

+0

@codeholic: D'accord, je pense que tout dans ma réponse est un faux-fuyant - vous semblez avoir quelque chose d'autre qui se passe. c'est-à-dire que "quelque chose" passe incorrectement l'attribut AutoCommit. Ce problème est-il quelque chose de nouveau qui vient de commencer ou l'avez-vous toujours eu? Je suppose qu'il se passe quelque chose de bizarre dans tes configs. – Ether

Questions connexes