Re: mod_perl2 + fork + DBI = Chaos
Tosh Cooey <[email protected]>
| Newsgroups | gmane.comp.apache.mod-perl |
|---|---|
| Organization | Twelve Hundred Group LLC |
| Message-ID | <[email protected]> |
Just to tie this thread up...
In case anyone else is ever in the same situation I would like to tell
them that mod_perl(1|2) + fork = bad idea, and don't even THINK about
throwing DBI into the mix.
For me in the future, if I have a VERY long task I will externalize it,
and if I have brief but long tasks then the following worked great for me:
#!/usr/bin/perl
use strict;
use Apache2::Const -compile => qw(:conn_keepalive);
use Apache2::Log(); # defines warn
use Apache2::RequestUtil(); # defines push_handlers
use Apache2::Connection();
use Apache2::RequestRec();
my $r = shift;
my $c = $r->connection();
$c->keepalive(Apache2::Const::CONN_CLOSE);
$r->push_handlers(PerlCleanupHandler => \&cleanup );
$r->err_headers_out->set(Location => 'http://...index.pl);
$r->status(Apache2::Const::REDIRECT);
return Apache2::Const::REDIRECT;
sub cleanup { # long process
my ($r) = @_;
$r->warn("Starting cleanup");
foreach my $num (1..5) {
$r->warn("Number is $num");
sleep 2;
}
return Apache2::Const::OK;
}
####
YMMV.
Tosh
[email protected] wrote:
> at(1) is a Unix command to start a process.
> Assuming you're on a Unix/Linux box, type "man at" to get the story.
>
> A cleanup handler is more pleasant than a prostate exam.
>
> You can spend your life waiting for others. Just write a
> routine called "cleanup" and have it do something like
> make a log entry.
>
> use Apache2::Const(); # defines OK
> use Apache2::Log(); # defines warn
> use Apache2::RequestUtil(); # defines push_handlers
> ...
> sub cleanup {
> my ($r) = @_;
> $r->warn("cleanup was here");
> return Apache2::Const::OK;
> }
> Then put a call like the one below in your ModPerl::Registry routine.
> If the log entry shows up in error_log, you're on your way...
>
> Good Luck,
> cmac
>
> P.S. Google doesn't index some sites well.
> Look at http://perl.apache.org/docs/2.0/
> particularly its API link.
>
>
> On Jan 25, 2010, at 5:49 PM, Tosh Cooey wrote:
>
>> Sorry, I couldn't figure out what at(1) meant (or maybe ap(1) which
>> you say below) is that an abbreviation for something?
>>
>> And Perrin saying "cleanup handler" is right up there with "prostate
>> exam" in my list of things to get into, both scare me!
>>
>> Of course at some point a man needs to do both...
>>
>> So... If this magic: $r->push_handlers(PerlCleanupHandler =>
>> \&cleanup); is available in ModPerl::Registry context then I will
>> attempt to force all my forks into early retirement and work the
>> problem out that way.
>>
>> Unfortunately Google doesn't return an easy answer, anybody know this
>> before I spend all day tomorrow in my struggle?
>>
>> Thank-you all again,
>>
>> Tosh
>>
>>
>> [email protected] wrote:
>>> You made no comment on the links I sent you earlier today.
>>> They had lots of good advice. Particularly the first one
>>> suggested not forking the Apache process, but using an
>>> ap(1) call to start a process to do the additional processing.
>>> OK, the ap(1) alternative was a bit light on details.
>>> How about the alternative offered by Perrin Hawkins in the
>>> same thread, of using a cleanup handler to do the follow-up
>>> processing rather than a forked process.
>>> From p. 107 of "mod_per2 User's Guide":
>>> $r->push_handlers(PerlCleanupHandler => \&cleanup);
>>>> print $in->redirect... # to redirect the browser
>>> Now cleanup (which receives $r as its operand) can do
>>> whatever slow stuff you need to, can probably use DBI
>>> without all the pain you have below, and can access the
>>> request to find out what to do.
>>> In some past context you may have learned how to get hold of
>>> a $r to use in these calls, and hopefully you're no longer
>>> scared of $r. But there does remain the question of whether
>>> a ModPerl::Registry module can do such calls.
>>> Hopefully someone who knows can chime in on this.
>>> If not, for me it would be worth the editing of getting the
>>> module out from under ModPerl::Registry and into the "native
>>> mode" of SetHandler modperl.
>>> Best of luck,
>>> cmac
>>> On Jan 25, 2010, at 1:54 PM, Tosh Cooey wrote:
>>>> Ok, then maybe I need to supply some code here to try and get
>>>> clarification:
>>>>
>>>> mailfile.pl
>>>> ###########
>>>> use strict;
>>>> ...
>>>> use POSIX;
>>>>
>>>> #gather needed modules and objects
>>>> my $fileOBJ = new MyOBJS::FILE($in->param('id'));
>>>> my $clientOBJ = new ...
>>>> my $userOBJ = new ...
>>>> # All OBJjects have a {DBH} property which is their DB handle
>>>> # I hear I have to disconnect these first, do I have to disconnect ALL?
>>>> $fileOBJ->{DBH}->disconnect;
>>>> $SIG{CHLD} = 'IGNORE';
>>>> my $pid;
>>>> if ($pid = fork) {
>>>> warn "Pid = $pid";
>>>> } elsif (defined $pid) {
>>>> close(STDOUT);
>>>> close(STDIN);
>>>> close(STDERR);
>>>>
>>>> # 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, '>/tmp/stderr' or die "Can't write to /tmp/stderr:
>>>> $!";
>>>> # Prevent locking to apache process
>>>> setsid or die "Can't start a new session: $!";
>>>>
>>>> # Create file download link email
>>>> my $mailSTR = ...
>>>>
>>>> # Send the mail possibly to many people
>>>> foreach my $person (@people) {
>>>> open(MAIL, '|' . &cfg('sendmail_location') . ' -t');
>>>> print MAIL $mailSTR;
>>>> close(MAIL);
>>>> }
>>>>
>>>> # Need to recreate the DBI connection on the $fileOBJ I hear
>>>> $fileOBJ = new MyOBJS::FILE($in->param('id'));
>>>>
>>>> # Do some SQL to update the $fileOBJ status based on mailout
>>>> $fileOBJ->sql....
>>>>
>>>> # create LOGGING Objects to log stuff
>>>> my $logOBJ = new ...
>>>> $logOBJ->sql...
>>>>
>>>> CORE::exit(0);
>>>> }
>>>>
>>>> print $in->redirect... # For the parent to redirect the browser
>>>>
>>>> # Done.
>>>>
>>>> Is there a glaring mistake in the above?
>>>>
>>>> The parent does no more DB stuff, it just sends a redirect.
>>>>
>>>> This runs under ModPerl::Registry.
>>>>
>>>> I'd like to get at least one thing working tonight, either the
>>>> forking or the DBI, I'll be happy!
>>>>
>>>> Tosh
>>>>
>>>>
>>>>
>>>> Perrin Harkins wrote:
>>>>> On Mon, Jan 25, 2010 at 3:48 PM, Tosh Cooey <[email protected]>
>>>>> wrote:
>>>>>> Thanks Perrin, the forking, my child got a PID of 30033 and then
>>>>>> afterwards
>>>>>> when I checked the processes (ps) for 30033 I see:
>>>>>>
>>>>>> [apache2] <defunct>
>>>>>>
>>>>>> Is that what's supposed to happen?
>>>>> After you call exit? No. It should be gone. That's a zombie
>>>>> process.
>>>>>> That PM thread seems to indicate that I must disconnect every DBH,
>>>>>> not just
>>>>>> the ones that I will use.
>>>>> Either that, or you need to set InactiveDestroy on all of them in the
>>>>> child process. Otherwise, when the child exits, it messes up all of
>>>>> them for the parent.
>>>>>> Are you also suggesting the use of
>>>>>> Parallel::ForkManager for forks?
>>>>> No. The DBI stuff is the same with either.
>>>>> - Perrin
>>>>
>>>> --
>>>> McIntosh Cooey - Twelve Hundred Group LLC - http://www.1200group.com/
>>
>> --
>> McIntosh Cooey - Twelve Hundred Group LLC - http://www.1200group.com/
>
>
--
McIntosh Cooey - Twelve Hundred Group LLC - http://www.1200group.com/