2009-01-23 6 views
7

Je rencontre des problèmes lors de l'exécution d'un processus de longue durée à partir d'un code exécuté sous mod_perl2. Tout fonctionne pour la plupart, mais il semble que le processus forké maintienne les poignées ouvertes dans les fichiers de log d'Apache - cela signifie qu'Apache ne redémarrera pas pendant que le processus est en cours (je reçois un message 'failed to open logfiles') .Comment est-ce que je branche correctement avec mod_perl2?

Voici le code que je utilise:

use POSIX; # required for setsid 

# Do not wait for child processes to complete 
$SIG{CHLD} = 'IGNORE'; 

# fork (and make sure we did!) 
defined (my $kid = fork) or die "Cannot fork: $!\n"; 

if ($kid) { 
    return (1, $kid); 
}else { 
    # chdir to /, stops the process from preventing an unmount 
    chdir '/' or die "Can't chdir to /: $!"; 

    # dump our STDIN and STDOUT handles 
    open STDIN, '/dev/null' or die "Can't read /dev/null: $!"; 
    open STDOUT, '>/dev/null' or die "Can't write to /dev/null: $!"; 

    # redirect for logging 
    open STDERR, '>', $log_filename or die "Can't write to log: $!"; 

    # Prevent locking to apache process 
    setsid or die "Can't start a new session: $!"; 

    # execute the command 
    exec($cmd, @args); 

    die "Failed to exec"; 
} 

Retour dans les jours mod_perl1, je me souviens à l'aide $r->cleanup_for_exec pour résoudre ce problème, mais il ne semble pas être pris en charge sous mod_perl2. (Edit: Apparently ce n'est plus nécessaire ..)

Un conseil pour lancer correctement un processus long-fonctionnel sur mod_perl2 sans ces problèmes serait le bienvenu! Essayez de fermer vos poignées STDIN/STDOUT avant le fork.

+0

Salut Dan, comment avez-vous résolu ce problème, je suis confronté au même problème. Plus tôt, j'utilisais mod_perl1 et '$ r-> cleanup_for_exec' fonctionnait bien mais dans mod_perl2 ce n'est plus nécessaire, alors pourriez-vous m'aider à implémenter ceci dans mod_perl2? Merci d'avance. –

Répondre

2

Vous voulez probablement lire this discussion. Il semble que vous ne devriez pas utiliser fork sur mod_perl à moins de savoir comment préparer les choses. Vous devez utiliser un module comme Apache2::SubProcess

1

+0

Cela casserait complètement Apache .. Le processus parent doit encore produire une réponse (et l'envoyer via STDOUT) pour le client. – Dan

+0

Le processus parent pourrait envoyer sa réponse avant de forking; à moins que vous ne fassiez plus de travail dans le parent après la fourchette. Si les fichiers journaux ne figurent pas dans les descripteurs STDIN/OUT/ERR, vous pouvez simplement commencer à fermer les descripteurs ouverts> 2 que vous trouvez dans le processus fils. – nezroy

+0

Ouais le problème est que le processus apache continue à servir d'autres requêtes quand il a fini celui-ci, en détruisant son STDERR brise sa journalisation, et je soupçonne que tuer son STDIN l'empêche de communiquer avec le proc parent. Quoi qu'il en soit - j'ai essayé et cela ne résout pas le problème;) – Dan

0

Dans mon (anciennement mod_perl, maintenant FCGI) code, j'ai dans la clause "else" du "if (kpid $)",

close STDIN; 
    close STDOUT; 
    close STDERR; 
    setsid(); 

En outre, pour des raisons que j'ai oublié, je me suis immédiatement fork à nouveau, puis enfant rouvrir STDIN, STDOUT et STDERR.

il ressemble:

$SIG{CHLD} = 'IGNORE'; 

# This should flush stdout. 
my $ofh = select(STDOUT);$| = 1;select $ofh; 

my $kpid = fork; 
if ($kpid) 
{ 
    # Parent process 
    waitpid($kpid, 0); 
} 
else 
{ 
    close STDIN; 
    close STDOUT; 
    close STDERR; 
    setsid(); 
    my $gpid = fork; 
    if (!$gpid) 
    { 
     open(STDIN, "</dev/null") ;#or print DEBUG2 "can't redirect stdin\n"; 
     open(STDOUT, ">/dev/null") ;#or print DEBUG2 "can't redirect stdout\n"; 
     open(STDERR, ">/dev/null") ;#or print DEBUG2 "can't redirect stderr\n"; 
     # Child process 
     exec($pgm, @execargs) ;# or print DEBUG2 "exec failed\n"; 
    } 
    exit 0; 
}