Re: mod_perl v2 Forking
Cameron B. Prince wrote: I have a report generator program written in Perl that I need to start from a CGI. The program takes about 15 minutes to run, so I must fork or double fork. I have two goals: 1) Have no zombies when the program completes 2) Fork in such a way that restarting Apache doesn't kill the forked process. I tried out the code here which is for mod_perl v1: http://perl.apache.org/docs/1.0/guide/performance.html#Forking_and_Executing _Subprocesses_from_mod_perl There are two problems with the code listed in the example: 1) Apache::SubProcess doesn't seem to contain the same methods as the older version. most of them aren't needed (they don't exist in the Apache 2.0 API. 2) open isn't working. (I've already been down this road and switched another call to an external program to use IPC::Run, but that program doesn't take long and needs no fork.) what open()? what's not working? please be more specific, show us some code and the actual error messages. Are you talking about open in http://perl.apache.org/docs/1.0/guide/performance.html#A_Complete_Fork_Example ? I took out the parts of the code that caused problems and ended up with this: $SIG{CHLD} = 'IGNORE'; defined (my $pid = fork) or die Cannot fork: $!\n; unless ($pid) { exec $command; CORE::exit(0); } This works and accomplishes my first goal, but not the second. If I start the program and restart Apache, the program is killed. have you detached the session as explained here? http://perl.apache.org/docs/1.0/guide/performance.html#Detaching_the_Forked_Process I admit I haven't tried this code from the above url with 2.0 yet (and it'd be nice to have such a test (hint! hint!)) but I can't see it in your sample, so I assume that you haven't tried it ;) Also while you are at it, once you figure out all the quirks if you can help us porting http://perl.apache.org/docs/1.0/guide/performance.html#Forking_and_Executing_Subprocesses_from_mod_perl to 2.0 docs that would be very helpful for those coming after you. Thanks. __ Stas BekmanJAm_pH -- Just Another mod_perl Hacker http://stason.org/ mod_perl Guide --- http://perl.apache.org mailto:[EMAIL PROTECTED] http://use.perl.org http://apacheweek.com http://modperlbook.org http://apache.org http://ticketmaster.com
Re: mod_perl v2 Forking
Hi, I guess this is off topic for this list, since I would be doing this no matter if I was running CGI or mod_perl or whatever. I am pretty desparate to get this working, and if anyone wants to earn some cash helping me fix things PLEASE call me at 250 655-9513. I have been trying to accomplish the same thing as Cameron, but with the detaching stuff it seemed a lot easier to make a server with IO::Select and not actually start the server from mod_perl. The end result hopefully will be a web user being able to start some things that take time, but not screw things up by interrupting them. But then I found I was using 5.8.. Thanks to a guy on comp.lang.perl.misc I know that there is a change in how signals are handled, they call it deferred signal handling because Perl now is suppose to wait until the Interpeter is in a safe state. As I understand it this might avoid some things like core dumps or other errors related to dieing while trying to do something besides dieing. The thing is somehow this ends up killing off my parent process, just like in this post: http://www.mail-archive.com/[EMAIL PROTECTED]/msg43989.html So this is happening to me as well, however the guy in the above example had his problem solved by using Errno and looking for EINTR if that error is raised then catch it and move on, I did get one maybe helpfull thing from my log: Erro was %! ./franken_socket.pl 8607: got - CHLD at Tue Sep 16 02:17:42 2003 I got forked ./franken_socket.pl 8599: begat 8607 at Tue Sep 16 02:17:40 2003 begat 8607 ./franken_socket.pl 8599: got - CHLD at Tue Sep 16 02:17:54 2003 ./franken_socket.pl 8599: main 8607 -- reaped 1 at Tue Sep 16 02:17:54 2003 reaped 1Erro was No child processes %! So it looks like the parent got killed on that error No child process This code works just fine on 5.6 since it is about 150% from examples :) The above is the result of connecting, doing a who, and doing dienow to test the alarm. I also found this: http://archive.develooper.com/[EMAIL PROTECTED]/msg03022.html Which totaly describes my problem as well, but shows it happening with perl 5.8.1.. I'd imagine that your accept() isn't being restarted. How does it work if you change the loop to look like this? use Errno; while (1) { my $client = $server-accept or do { next if $!{EINTR}; last; }; spawn(\function, whatever); } #!/usr/bin/perl -w ## new frankenstein! use strict; use POSIX (); use POSIX 'WNOHANG'; use Errno; use IO::Socket; use FindBin (); use File::Basename (); use File::Spec::Functions; use Net::hostent; use Carp; $|=1; my $pid; open (DIED, /var/log/daemon_log) or warn $!; sub logmsg { print DIED $0 $$: @_ at , scalar localtime, \n } my $listen_socket = IO::Socket::INET-new(LocalPort = 1081, LocalAddr = '127.0.0.1', Proto = 'tcp', Listen= SOMAXCONN, Reuse = 1 ) or die can make a tcp server on port 1080 $!; # make the daemon cross-platform, so exec always calls the script # itself with the right path, no matter how the script was invoked. my $script = File::Basename::basename($0); my $SELF = catfile $FindBin::Bin, $script; # POSIX unmasks the sigprocmask properly my $sigset = POSIX::SigSet-new(); my $action = POSIX::SigAction-new('sigHUP_handler', $sigset, POSIX::SA_NODEFER); my $action_alrm = POSIX::SigAction-new('sigALRM_handler', $sigset, POSIX::SA_NODEFER); POSIX::sigaction(POSIX::SIGHUP, $action); POSIX::sigaction(POSIX::SIGALRM, $action_alrm); sub sigHUP_handler { print got SIGHUP\n; exec($SELF, @ARGV) or die Couldn't restart: $!\n; } sub sigALRM_handler { print got ALARM timeout\n; } $SIG{CHLD} = \REAPER_NEW; sub REAPER { $SIG{CHLD} = \REAPER; # loathe sysV my $waitedpid = wait; logmsg reaped $waitedpid . ($? ? with exit $? : ''); } sub REAPER_NEW { logmsg got - @_\n; my $wpid = undef; while ($wpid = waitpid(-1,WNOHANG)0) { logmsg main $pid -- reaped $wpid . ($? ? with exit $? : '') ; print DIED reaped $wpid . ($? ? with exit $? : ''); } } print PID: $$\n; print ARGV: @ARGV\n; print [Server $0 accepting clients]\n; #while (my $connection = $listen_socket-accept()) { while (1) { my $connection = $listen_socket-accept() or do { next if $!{EINTR}; last; }; print DIED Erro was $! %! \n; $connection-autoflush(1); ## missing seemed to cause client problem, but not telnet if (!defined($pid = fork)) { logmsg cannot fork: $!; }elsif
Re: mod_perl v2 Forking
Eric Frazier wrote: ... But then I found I was using 5.8.. Thanks to a guy on comp.lang.perl.misc I know that there is a change in how signals are handled, they call it deferred signal handling because Perl now is suppose to wait until the Interpeter is in a safe state. As I understand it this might avoid some things like core dumps or other errors related to dieing while trying to do something besides dieing. Mostly, yes. Look at the perldelta manpage that is distributed with perl 5.8.0, section Safe Signals. If you want to restore the 5.6-ish unsafe signal handling, this is not possible with 5.8.0 :(. But, as it has been acknowledged that this unsafe behaviour is desirable in some cases, it will be possible with perl 5.8.1. You can grab a 5.8.1 release candidate 4 from CPAN : http://search.cpan.org/~jhi/ (RC5 should be out in a few days) and see with it if using unsafe signal handlers solves your problem. You can enable them with the PERL_SIGNALS environment variable. Here's the relevant part of the perlrun manpage that comes with perl 5.8.1 RC4 : =item PERL_SIGNALS In Perls 5.8.1 and later. If set to Cunsafe the pre-Perl-5.8.0 signals behaviour (immediate but unsafe) is restored. If set to Csafe the safe (or deferred) signals are used. See Lperlipc/Deferred Signals (Safe signals). HTH.
RE: mod_perl v2 Forking
Hi, I had a problem with 5.8.1 and forking in that I was either getting zombies using the 5.6 examples or the parent was dying, depending on which example was used. The way round I found was to: # ignore the child, good rule for life $SIG{CHLD} = 'IGNORE'; # then sort out the socket my $server = new IO::Socket::INET(LocalPort = $port, Type = SOCK_STREAM, Proto = tcp, Listen = 5) or die some error; # wait for a connection while(my $client = $server-accept()) { my $pid = fork; die Error. Fork: $!\n unless defined $pid; if($pid == 0) { # all your child code here # when it's done, kill the child: exit(0); } } This seemes reasonably stable. If anybody has a better way, then I'm all ears. Cheers! -Original Message- From: Eric Frazier [mailto:[EMAIL PROTECTED] Sent: 16 September 2003 12:24 To: [EMAIL PROTECTED] Cc: [EMAIL PROTECTED] Subject: Re: mod_perl v2 Forking Hi, I guess this is off topic for this list, since I would be doing this no matter if I was running CGI or mod_perl or whatever. I am pretty desparate to get this working, and if anyone wants to earn some cash helping me fix things PLEASE call me at 250 655-9513. I have been trying to accomplish the same thing as Cameron, but with the detaching stuff it seemed a lot easier to make a server with IO::Select and not actually start the server from mod_perl. The end result hopefully will be a web user being able to start some things that take time, but not screw things up by interrupting them. But then I found I was using 5.8.. Thanks to a guy on comp.lang.perl.misc I know that there is a change in how signals are handled, they call it deferred signal handling because Perl now is suppose to wait until the Interpeter is in a safe state. As I understand it this might avoid some things like core dumps or other errors related to dieing while trying to do something besides dieing. The thing is somehow this ends up killing off my parent process, just like in this post: http://www.mail-archive.com/[EMAIL PROTECTED]/msg43989.html So this is happening to me as well, however the guy in the above example had his problem solved by using Errno and looking for EINTR if that error is raised then catch it and move on, I did get one maybe helpfull thing from my log: Erro was %! ./franken_socket.pl 8607: got - CHLD at Tue Sep 16 02:17:42 2003 I got forked ./franken_socket.pl 8599: begat 8607 at Tue Sep 16 02:17:40 2003 begat 8607 ./franken_socket.pl 8599: got - CHLD at Tue Sep 16 02:17:54 2003 ./franken_socket.pl 8599: main 8607 -- reaped 1 at Tue Sep 16 02:17:54 2003 reaped 1Erro was No child processes %! So it looks like the parent got killed on that error No child process This code works just fine on 5.6 since it is about 150% from examples :) The above is the result of connecting, doing a who, and doing dienow to test the alarm. I also found this: http://archive.develooper.com/[EMAIL PROTECTED]/msg03022.html Which totaly describes my problem as well, but shows it happening with perl 5.8.1.. I'd imagine that your accept() isn't being restarted. How does it work if you change the loop to look like this? use Errno; while (1) { my $client = $server-accept or do { next if $!{EINTR}; last; }; spawn(\function, whatever); } #!/usr/bin/perl -w ## new frankenstein! use strict; use POSIX (); use POSIX 'WNOHANG'; use Errno; use IO::Socket; use FindBin (); use File::Basename (); use File::Spec::Functions; use Net::hostent; use Carp; $|=1; my $pid; open (DIED, /var/log/daemon_log) or warn $!; sub logmsg { print DIED $0 $$: @_ at , scalar localtime, \n } my $listen_socket = IO::Socket::INET-new(LocalPort = 1081, LocalAddr = '127.0.0.1', Proto = 'tcp', Listen= SOMAXCONN, Reuse = 1 ) or die can make a tcp server on port 1080 $!; # make the daemon cross-platform, so exec always calls the script # itself with the right path, no matter how the script was invoked. my $script = File::Basename::basename($0); my $SELF = catfile $FindBin::Bin, $script; # POSIX unmasks the sigprocmask properly my $sigset = POSIX::SigSet-new(); my $action = POSIX::SigAction-new('sigHUP_handler', $sigset, POSIX::SA_NODEFER); my $action_alrm = POSIX::SigAction-new('sigALRM_handler', $sigset, POSIX::SA_NODEFER); POSIX::sigaction(POSIX::SIGHUP, $action); POSIX::sigaction(POSIX::SIGALRM, $action_alrm); sub sigHUP_handler { print got SIGHUP\n; exec($SELF, @ARGV
Re: mod_perl v2 Forking
Hi, That sound like one way to go, I want to be very careful with something like this. You speak as if restoring 5.6 behaviour is the best or only way to go. Do you see any other alternatives? Thanks, Eric At 04:57 PM 9/16/03 +0200, Rafael Garcia-Suarez wrote: Eric Frazier wrote: ... But then I found I was using 5.8.. Thanks to a guy on comp.lang.perl.misc I know that there is a change in how signals are handled, they call it deferred signal handling because Perl now is suppose to wait until the Interpeter is in a safe state. As I understand it this might avoid some things like core dumps or other errors related to dieing while trying to do something besides dieing. Mostly, yes. Look at the perldelta manpage that is distributed with perl 5.8.0, section Safe Signals. I did read that, it seems kind of misleading. The 5.8 IPC doc was more helpful, but I still didn't get a clear idea how to handle this and the examples are not updated yet. If you want to restore the 5.6-ish unsafe signal handling, this is not possible with 5.8.0 :(. But, as it has been acknowledged that this unsafe behaviour is desirable in some cases, it will be possible with perl 5.8.1. You can grab a 5.8.1 release candidate 4 from CPAN : http://search.cpan.org/~jhi/ (RC5 should be out in a few days) and see with it if using unsafe signal handlers solves your problem. You can enable them with the PERL_SIGNALS environment variable. Here's the relevant part of the perlrun manpage that comes with perl 5.8.1 RC4 : =item PERL_SIGNALS In Perls 5.8.1 and later. If set to Cunsafe the pre-Perl-5.8.0 signals behaviour (immediate but unsafe) is restored. If set to Csafe the safe (or deferred) signals are used. See Lperlipc/Deferred Signals (Safe signals). HTH. (250) 655 - 9513 (PST Time Zone) Inquiry is fatal to certainty. -- Will Durant
RE: mod_perl v2 Forking
Hi, Doing this works for me. But I am ending up with some errors that I didn't have before. Of course my bosses would get mad if I posted all of the code involed, but basicly a database connection that was working fine is now returning mysql server has gone away, meaning that the connection got killed. What is weird/scary, is that if I change your $SIG{CHLD} = 'IGNORE'; back to the handler I was using, the database error goes away, but I am back were I was. Fun huh? :) Thanks, Eric At 03:57 PM 9/16/03 +0100, Stephen Hardisty wrote: Hi, I had a problem with 5.8.1 and forking in that I was either getting zombies using the 5.6 examples or the parent was dying, depending on which example was used. The way round I found was to: # ignore the child, good rule for life $SIG{CHLD} = 'IGNORE'; # then sort out the socket my $server = new IO::Socket::INET(LocalPort = $port, Type = SOCK_STREAM, Proto = tcp, Listen = 5) or die some error; # wait for a connection while(my $client = $server-accept()) { my $pid = fork; die Error. Fork: $!\n unless defined $pid; if($pid == 0) { # all your child code here # when it's done, kill the child: exit(0); } } This seemes reasonably stable. If anybody has a better way, then I'm all ears. Cheers! -Original Message- From: Eric Frazier [mailto:[EMAIL PROTECTED] Sent: 16 September 2003 12:24 To: [EMAIL PROTECTED] Cc: [EMAIL PROTECTED] Subject: Re: mod_perl v2 Forking Hi, I guess this is off topic for this list, since I would be doing this no matter if I was running CGI or mod_perl or whatever. I am pretty desparate to get this working, and if anyone wants to earn some cash helping me fix things PLEASE call me at 250 655-9513. I have been trying to accomplish the same thing as Cameron, but with the detaching stuff it seemed a lot easier to make a server with IO::Select and not actually start the server from mod_perl. The end result hopefully will be a web user being able to start some things that take time, but not screw things up by interrupting them. But then I found I was using 5.8.. Thanks to a guy on comp.lang.perl.misc I know that there is a change in how signals are handled, they call it deferred signal handling because Perl now is suppose to wait until the Interpeter is in a safe state. As I understand it this might avoid some things like core dumps or other errors related to dieing while trying to do something besides dieing. The thing is somehow this ends up killing off my parent process, just like in this post: http://www.mail-archive.com/[EMAIL PROTECTED]/msg43989.html So this is happening to me as well, however the guy in the above example had his problem solved by using Errno and looking for EINTR if that error is raised then catch it and move on, I did get one maybe helpfull thing from my log: Erro was %! ./franken_socket.pl 8607: got - CHLD at Tue Sep 16 02:17:42 2003 I got forked ./franken_socket.pl 8599: begat 8607 at Tue Sep 16 02:17:40 2003 begat 8607 ./franken_socket.pl 8599: got - CHLD at Tue Sep 16 02:17:54 2003 ./franken_socket.pl 8599: main 8607 -- reaped 1 at Tue Sep 16 02:17:54 2003 reaped 1Erro was No child processes %! So it looks like the parent got killed on that error No child process This code works just fine on 5.6 since it is about 150% from examples :) The above is the result of connecting, doing a who, and doing dienow to test the alarm. I also found this: http://archive.develooper.com/[EMAIL PROTECTED]/msg03022.html Which totaly describes my problem as well, but shows it happening with perl 5.8.1.. I'd imagine that your accept() isn't being restarted. How does it work if you change the loop to look like this? use Errno; while (1) { my $client = $server-accept or do { next if $!{EINTR}; last; }; spawn(\function, whatever); } #!/usr/bin/perl -w ## new frankenstein! use strict; use POSIX (); use POSIX 'WNOHANG'; use Errno; use IO::Socket; use FindBin (); use File::Basename (); use File::Spec::Functions; use Net::hostent; use Carp; $|=1; my $pid; open (DIED, /var/log/daemon_log) or warn $!; sub logmsg { print DIED $0 $$: @_ at , scalar localtime, \n } my $listen_socket = IO::Socket::INET-new(LocalPort = 1081, LocalAddr = '127.0.0.1', Proto = 'tcp', Listen= SOMAXCONN, Reuse = 1 ) or die can make a tcp server on port 1080 $!; # make the daemon cross-platform, so exec always calls the script # itself with the right path, no matter how the script was invoked. my $script = File::Basename::basename($0); my $SELF = catfile $FindBin::Bin, $script; # POSIX unmasks the sigprocmask
RE: mod_perl v2 Forking
Hi, is the database connection created in the child or before it? If it's created inside the child then it'll die ungracefully when the child dies, so put something nice and fluffy to close it before the exit. Otherwise, I don't know I'm afraid. -Original Message- From: Eric Frazier [mailto:[EMAIL PROTECTED] Sent: 16 September 2003 12:57 To: Stephen Hardisty Cc: [EMAIL PROTECTED] Subject: RE: mod_perl v2 Forking Hi, Doing this works for me. But I am ending up with some errors that I didn't have before. Of course my bosses would get mad if I posted all of the code involed, but basicly a database connection that was working fine is now returning mysql server has gone away, meaning that the connection got killed. What is weird/scary, is that if I change your $SIG{CHLD} = 'IGNORE'; back to the handler I was using, the database error goes away, but I am back were I was. Fun huh? :) Thanks, Eric At 03:57 PM 9/16/03 +0100, Stephen Hardisty wrote: Hi, I had a problem with 5.8.1 and forking in that I was either getting zombies using the 5.6 examples or the parent was dying, depending on which example was used. The way round I found was to: # ignore the child, good rule for life $SIG{CHLD} = 'IGNORE'; # then sort out the socket my $server = new IO::Socket::INET(LocalPort = $port, Type = SOCK_STREAM, Proto = tcp, Listen = 5) or die some error; # wait for a connection while(my $client = $server-accept()) { my $pid = fork; die Error. Fork: $!\n unless defined $pid; if($pid == 0) { # all your child code here # when it's done, kill the child: exit(0); } } This seemes reasonably stable. If anybody has a better way, then I'm all ears. Cheers! -Original Message- From: Eric Frazier [mailto:[EMAIL PROTECTED] Sent: 16 September 2003 12:24 To: [EMAIL PROTECTED] Cc: [EMAIL PROTECTED] Subject: Re: mod_perl v2 Forking Hi, I guess this is off topic for this list, since I would be doing this no matter if I was running CGI or mod_perl or whatever. I am pretty desparate to get this working, and if anyone wants to earn some cash helping me fix things PLEASE call me at 250 655-9513. I have been trying to accomplish the same thing as Cameron, but with the detaching stuff it seemed a lot easier to make a server with IO::Select and not actually start the server from mod_perl. The end result hopefully will be a web user being able to start some things that take time, but not screw things up by interrupting them. But then I found I was using 5.8.. Thanks to a guy on comp.lang.perl.misc I know that there is a change in how signals are handled, they call it deferred signal handling because Perl now is suppose to wait until the Interpeter is in a safe state. As I understand it this might avoid some things like core dumps or other errors related to dieing while trying to do something besides dieing. The thing is somehow this ends up killing off my parent process, just like in this post: http://www.mail-archive.com/[EMAIL PROTECTED]/msg43989.html So this is happening to me as well, however the guy in the above example had his problem solved by using Errno and looking for EINTR if that error is raised then catch it and move on, I did get one maybe helpfull thing from my log: Erro was %! ./franken_socket.pl 8607: got - CHLD at Tue Sep 16 02:17:42 2003 I got forked ./franken_socket.pl 8599: begat 8607 at Tue Sep 16 02:17:40 2003 begat 8607 ./franken_socket.pl 8599: got - CHLD at Tue Sep 16 02:17:54 2003 ./franken_socket.pl 8599: main 8607 -- reaped 1 at Tue Sep 16 02:17:54 2003 reaped 1Erro was No child processes %! So it looks like the parent got killed on that error No child process This code works just fine on 5.6 since it is about 150% from examples :) The above is the result of connecting, doing a who, and doing dienow to test the alarm. I also found this: http://archive.develooper.com/[EMAIL PROTECTED]/msg03022.html Which totaly describes my problem as well, but shows it happening with perl 5.8.1.. I'd imagine that your accept() isn't being restarted. How does it work if you change the loop to look like this? use Errno; while (1) { my $client = $server-accept or do { next if $!{EINTR}; last; }; spawn(\function, whatever); } #!/usr/bin/perl -w ## new frankenstein! use strict; use POSIX (); use POSIX 'WNOHANG'; use Errno; use IO::Socket; use FindBin (); use File::Basename (); use File::Spec::Functions; use Net::hostent; use Carp; $|=1; my $pid; open (DIED, /var/log/daemon_log) or warn $!; sub logmsg { print DIED $0 $$: @_ at , scalar localtime, \n } my $listen_socket = IO::Socket::INET-new(LocalPort = 1081, LocalAddr = '127.0.0.1', Proto
RE: mod_perl v2 Forking
Hi, Well, I am not sure if this is going to be the best solution long term, but it works! while ( $connection ){ my $return_value = undef; if(/quit|exit/i){ last;} elsif (/closeme/i ) {$connection-close(); } elsif (/date|time/i){ printf $connection %s\n, scalar localtime; exit(0); } that did call to a sub, and then connected to a database. I am wondering if that connection object is better off being global. I changed the connect to be global, restarted and did a test and it worked fine! I was all ready to post back to here with the good news, when just to double check I went back and made the db connect in the local sub like before. And it still worked?! So it seems like I might be in better shape for now, but I might have some long term problems with DB connections dieing, most likely related to this child handling. I have to think that becase the query I am doing is VERY well tested and never causes an issue. Thanks tremedously for everyone's help so far, I at the very least have some directions to go in now. I still would very much like to learn what the correct, put it in the book solution should be.. Eric At 03:57 PM 9/16/03 +0100, Stephen Hardisty wrote: Hi, I had a problem with 5.8.1 and forking in that I was either getting zombies using the 5.6 examples or the parent was dying, depending on which example was used. The way round I found was to: # ignore the child, good rule for life $SIG{CHLD} = 'IGNORE'; # then sort out the socket my $server = new IO::Socket::INET(LocalPort = $port, Type = SOCK_STREAM, Proto = tcp, Listen = 5) or die some error; # wait for a connection while(my $client = $server-accept()) { my $pid = fork; die Error. Fork: $!\n unless defined $pid; if($pid == 0) { # all your child code here # when it's done, kill the child: exit(0); } } This seemes reasonably stable. If anybody has a better way, then I'm all ears. Cheers! -Original Message- From: Eric Frazier [mailto:[EMAIL PROTECTED] Sent: 16 September 2003 12:24 To: [EMAIL PROTECTED] Cc: [EMAIL PROTECTED] Subject: Re: mod_perl v2 Forking Hi, I guess this is off topic for this list, since I would be doing this no matter if I was running CGI or mod_perl or whatever. I am pretty desparate to get this working, and if anyone wants to earn some cash helping me fix things PLEASE call me at 250 655-9513. I have been trying to accomplish the same thing as Cameron, but with the detaching stuff it seemed a lot easier to make a server with IO::Select and not actually start the server from mod_perl. The end result hopefully will be a web user being able to start some things that take time, but not screw things up by interrupting them. But then I found I was using 5.8.. Thanks to a guy on comp.lang.perl.misc I know that there is a change in how signals are handled, they call it deferred signal handling because Perl now is suppose to wait until the Interpeter is in a safe state. As I understand it this might avoid some things like core dumps or other errors related to dieing while trying to do something besides dieing. The thing is somehow this ends up killing off my parent process, just like in this post: http://www.mail-archive.com/[EMAIL PROTECTED]/msg43989.html So this is happening to me as well, however the guy in the above example had his problem solved by using Errno and looking for EINTR if that error is raised then catch it and move on, I did get one maybe helpfull thing from my log: Erro was %! ./franken_socket.pl 8607: got - CHLD at Tue Sep 16 02:17:42 2003 I got forked ./franken_socket.pl 8599: begat 8607 at Tue Sep 16 02:17:40 2003 begat 8607 ./franken_socket.pl 8599: got - CHLD at Tue Sep 16 02:17:54 2003 ./franken_socket.pl 8599: main 8607 -- reaped 1 at Tue Sep 16 02:17:54 2003 reaped 1Erro was No child processes %! So it looks like the parent got killed on that error No child process This code works just fine on 5.6 since it is about 150% from examples :) The above is the result of connecting, doing a who, and doing dienow to test the alarm. I also found this: http://archive.develooper.com/[EMAIL PROTECTED]/msg03022.html Which totaly describes my problem as well, but shows it happening with perl 5.8.1.. I'd imagine that your accept() isn't being restarted. How does it work if you change the loop to look like this? use Errno; while (1) { my $client = $server-accept or do { next if $!{EINTR}; last; }; spawn(\function, whatever); } #!/usr/bin/perl -w ## new frankenstein! use strict; use POSIX (); use POSIX 'WNOHANG'; use Errno; use IO::Socket; use FindBin (); use File::Basename
RE: mod_perl v2 Forking
:) I think that makes sense. It was created in the child. It seemed to be fixed when I made the connection global. When I tried the connection in the child again it might well have been a lucky transpireing of events that let the child stay alive long enough for the query to get completed. So I should keep it global I think. Thanks, Eric At 04:24 PM 9/16/03 +0100, Stephen Hardisty wrote: Hi, is the database connection created in the child or before it? If it's created inside the child then it'll die ungracefully when the child dies, so put something nice and fluffy to close it before the exit. Otherwise, I don't know I'm afraid. -Original Message- From: Eric Frazier [mailto:[EMAIL PROTECTED] Sent: 16 September 2003 12:57 To: Stephen Hardisty Cc: [EMAIL PROTECTED] Subject: RE: mod_perl v2 Forking Hi, Doing this works for me. But I am ending up with some errors that I didn't have before. Of course my bosses would get mad if I posted all of the code involed, but basicly a database connection that was working fine is now returning mysql server has gone away, meaning that the connection got killed. What is weird/scary, is that if I change your $SIG{CHLD} = 'IGNORE'; back to the handler I was using, the database error goes away, but I am back were I was. Fun huh? :) Thanks, Eric At 03:57 PM 9/16/03 +0100, Stephen Hardisty wrote: Hi, I had a problem with 5.8.1 and forking in that I was either getting zombies using the 5.6 examples or the parent was dying, depending on which example was used. The way round I found was to: # ignore the child, good rule for life $SIG{CHLD} = 'IGNORE'; # then sort out the socket my $server = new IO::Socket::INET(LocalPort = $port, Type = SOCK_STREAM, Proto = tcp, Listen = 5) or die some error; # wait for a connection while(my $client = $server-accept()) { my $pid = fork; die Error. Fork: $!\n unless defined $pid; if($pid == 0) { # all your child code here # when it's done, kill the child: exit(0); } } This seemes reasonably stable. If anybody has a better way, then I'm all ears. Cheers! -Original Message- From: Eric Frazier [mailto:[EMAIL PROTECTED] Sent: 16 September 2003 12:24 To: [EMAIL PROTECTED] Cc: [EMAIL PROTECTED] Subject: Re: mod_perl v2 Forking Hi, I guess this is off topic for this list, since I would be doing this no matter if I was running CGI or mod_perl or whatever. I am pretty desparate to get this working, and if anyone wants to earn some cash helping me fix things PLEASE call me at 250 655-9513. I have been trying to accomplish the same thing as Cameron, but with the detaching stuff it seemed a lot easier to make a server with IO::Select and not actually start the server from mod_perl. The end result hopefully will be a web user being able to start some things that take time, but not screw things up by interrupting them. But then I found I was using 5.8.. Thanks to a guy on comp.lang.perl.misc I know that there is a change in how signals are handled, they call it deferred signal handling because Perl now is suppose to wait until the Interpeter is in a safe state. As I understand it this might avoid some things like core dumps or other errors related to dieing while trying to do something besides dieing. The thing is somehow this ends up killing off my parent process, just like in this post: http://www.mail-archive.com/[EMAIL PROTECTED]/msg43989.html So this is happening to me as well, however the guy in the above example had his problem solved by using Errno and looking for EINTR if that error is raised then catch it and move on, I did get one maybe helpfull thing from my log: Erro was %! ./franken_socket.pl 8607: got - CHLD at Tue Sep 16 02:17:42 2003 I got forked ./franken_socket.pl 8599: begat 8607 at Tue Sep 16 02:17:40 2003 begat 8607 ./franken_socket.pl 8599: got - CHLD at Tue Sep 16 02:17:54 2003 ./franken_socket.pl 8599: main 8607 -- reaped 1 at Tue Sep 16 02:17:54 2003 reaped 1Erro was No child processes %! So it looks like the parent got killed on that error No child process This code works just fine on 5.6 since it is about 150% from examples :) The above is the result of connecting, doing a who, and doing dienow to test the alarm. I also found this: http://archive.develooper.com/[EMAIL PROTECTED]/msg03022.html Which totaly describes my problem as well, but shows it happening with perl 5.8.1.. I'd imagine that your accept() isn't being restarted. How does it work if you change the loop to look like this? use Errno; while (1) { my $client = $server-accept or do { next if $!{EINTR}; last; }; spawn(\function, whatever); } #!/usr/bin/perl -w ## new frankenstein! use strict; use POSIX (); use POSIX 'WNOHANG'; use Errno; use IO::Socket
RE: mod_perl v2 Forking
Haven't read much of this thread, but is POE an option ? -Original Message- From: Eric Frazier [mailto:[EMAIL PROTECTED] Sent: 16 September 2003 13:17 To: Stephen Hardisty Cc: [EMAIL PROTECTED] Subject: RE: mod_perl v2 Forking :) I think that makes sense. It was created in the child. It seemed to be fixed when I made the connection global. When I tried the connection in the child again it might well have been a lucky transpireing of events that let the child stay alive long enough for the query to get completed. So I should keep it global I think. Thanks, Eric At 04:24 PM 9/16/03 +0100, Stephen Hardisty wrote: Hi, is the database connection created in the child or before it? If it's created inside the child then it'll die ungracefully when the child dies, so put something nice and fluffy to close it before the exit. Otherwise, I don't know I'm afraid. -Original Message- From: Eric Frazier [mailto:[EMAIL PROTECTED] Sent: 16 September 2003 12:57 To: Stephen Hardisty Cc: [EMAIL PROTECTED] Subject: RE: mod_perl v2 Forking Hi, Doing this works for me. But I am ending up with some errors that I didn't have before. Of course my bosses would get mad if I posted all of the code involed, but basicly a database connection that was working fine is now returning mysql server has gone away, meaning that the connection got killed. What is weird/scary, is that if I change your $SIG{CHLD} = 'IGNORE'; back to the handler I was using, the database error goes away, but I am back were I was. Fun huh? :) Thanks, Eric At 03:57 PM 9/16/03 +0100, Stephen Hardisty wrote: Hi, I had a problem with 5.8.1 and forking in that I was either getting zombies using the 5.6 examples or the parent was dying, depending on which example was used. The way round I found was to: # ignore the child, good rule for life $SIG{CHLD} = 'IGNORE'; # then sort out the socket my $server = new IO::Socket::INET(LocalPort = $port, Type = SOCK_STREAM, Proto = tcp, Listen = 5) or die some error; # wait for a connection while(my $client = $server-accept()) { my $pid = fork; die Error. Fork: $!\n unless defined $pid; if($pid == 0) { # all your child code here # when it's done, kill the child: exit(0); } } This seemes reasonably stable. If anybody has a better way, then I'm all ears. Cheers! -Original Message- From: Eric Frazier [mailto:[EMAIL PROTECTED] Sent: 16 September 2003 12:24 To: [EMAIL PROTECTED] Cc: [EMAIL PROTECTED] Subject: Re: mod_perl v2 Forking Hi, I guess this is off topic for this list, since I would be doing this no matter if I was running CGI or mod_perl or whatever. I am pretty desparate to get this working, and if anyone wants to earn some cash helping me fix things PLEASE call me at 250 655-9513. I have been trying to accomplish the same thing as Cameron, but with the detaching stuff it seemed a lot easier to make a server with IO::Select and not actually start the server from mod_perl. The end result hopefully will be a web user being able to start some things that take time, but not screw things up by interrupting them. But then I found I was using 5.8.. Thanks to a guy on comp.lang.perl.misc I know that there is a change in how signals are handled, they call it deferred signal handling because Perl now is suppose to wait until the Interpeter is in a safe state. As I understand it this might avoid some things like core dumps or other errors related to dieing while trying to do something besides dieing. The thing is somehow this ends up killing off my parent process, just like in this post: http://www.mail-archive.com/[EMAIL PROTECTED]/msg43989.html So this is happening to me as well, however the guy in the above example had his problem solved by using Errno and looking for EINTR if that error is raised then catch it and move on, I did get one maybe helpfull thing from my log: Erro was %! ./franken_socket.pl 8607: got - CHLD at Tue Sep 16 02:17:42 2003 I got forked ./franken_socket.pl 8599: begat 8607 at Tue Sep 16 02:17:40 2003 begat 8607 ./franken_socket.pl 8599: got - CHLD at Tue Sep 16 02:17:54 2003 ./franken_socket.pl 8599: main 8607 -- reaped 1 at Tue Sep 16 02:17:54 2003 reaped 1Erro was No child processes %! So it looks like the parent got killed on that error No child process This code works just fine on 5.6 since it is about 150% from examples :) The above is the result of connecting, doing a who, and doing dienow to test the alarm. I also found this: http://archive.develooper.com/[EMAIL PROTECTED]/msg03022.html Which totaly describes my problem as well, but shows
RE: mod_perl v2 Forking
I guess you could, but if there's already a load of code mightn't be a bit of a pain POE-ing it? -Original Message- From: Gareth Kirwan [mailto:[EMAIL PROTECTED] Sent: 16 September 2003 16:50 To: 'Eric Frazier'; Stephen Hardisty Cc: [EMAIL PROTECTED] Subject: RE: mod_perl v2 Forking Haven't read much of this thread, but is POE an option ? -Original Message- From: Eric Frazier [mailto:[EMAIL PROTECTED] Sent: 16 September 2003 13:17 To: Stephen Hardisty Cc: [EMAIL PROTECTED] Subject: RE: mod_perl v2 Forking :) I think that makes sense. It was created in the child. It seemed to be fixed when I made the connection global. When I tried the connection in the child again it might well have been a lucky transpireing of events that let the child stay alive long enough for the query to get completed. So I should keep it global I think. Thanks, Eric At 04:24 PM 9/16/03 +0100, Stephen Hardisty wrote: Hi, is the database connection created in the child or before it? If it's created inside the child then it'll die ungracefully when the child dies, so put something nice and fluffy to close it before the exit. Otherwise, I don't know I'm afraid. -Original Message- From: Eric Frazier [mailto:[EMAIL PROTECTED] Sent: 16 September 2003 12:57 To: Stephen Hardisty Cc: [EMAIL PROTECTED] Subject: RE: mod_perl v2 Forking Hi, Doing this works for me. But I am ending up with some errors that I didn't have before. Of course my bosses would get mad if I posted all of the code involed, but basicly a database connection that was working fine is now returning mysql server has gone away, meaning that the connection got killed. What is weird/scary, is that if I change your $SIG{CHLD} = 'IGNORE'; back to the handler I was using, the database error goes away, but I am back were I was. Fun huh? :) Thanks, Eric At 03:57 PM 9/16/03 +0100, Stephen Hardisty wrote: Hi, I had a problem with 5.8.1 and forking in that I was either getting zombies using the 5.6 examples or the parent was dying, depending on which example was used. The way round I found was to: # ignore the child, good rule for life $SIG{CHLD} = 'IGNORE'; # then sort out the socket my $server = new IO::Socket::INET(LocalPort = $port, Type = SOCK_STREAM, Proto = tcp, Listen = 5) or die some error; # wait for a connection while(my $client = $server-accept()) { my $pid = fork; die Error. Fork: $!\n unless defined $pid; if($pid == 0) { # all your child code here # when it's done, kill the child: exit(0); } } This seemes reasonably stable. If anybody has a better way, then I'm all ears. Cheers! -Original Message- From: Eric Frazier [mailto:[EMAIL PROTECTED] Sent: 16 September 2003 12:24 To: [EMAIL PROTECTED] Cc: [EMAIL PROTECTED] Subject: Re: mod_perl v2 Forking Hi, I guess this is off topic for this list, since I would be doing this no matter if I was running CGI or mod_perl or whatever. I am pretty desparate to get this working, and if anyone wants to earn some cash helping me fix things PLEASE call me at 250 655-9513. I have been trying to accomplish the same thing as Cameron, but with the detaching stuff it seemed a lot easier to make a server with IO::Select and not actually start the server from mod_perl. The end result hopefully will be a web user being able to start some things that take time, but not screw things up by interrupting them. But then I found I was using 5.8.. Thanks to a guy on comp.lang.perl.misc I know that there is a change in how signals are handled, they call it deferred signal handling because Perl now is suppose to wait until the Interpeter is in a safe state. As I understand it this might avoid some things like core dumps or other errors related to dieing while trying to do something besides dieing. The thing is somehow this ends up killing off my parent process, just like in this post: http://www.mail-archive.com/[EMAIL PROTECTED]/msg43989.html So this is happening to me as well, however the guy in the above example had his problem solved by using Errno and looking for EINTR if that error is raised then catch it and move on, I did get one maybe helpfull thing from my log: Erro was %! ./franken_socket.pl 8607: got - CHLD at Tue Sep 16 02:17:42 2003 I got forked ./franken_socket.pl 8599: begat 8607 at Tue Sep 16 02:17:40 2003 begat 8607 ./franken_socket.pl 8599: got - CHLD at Tue Sep 16 02:17:54 2003 ./franken_socket.pl 8599: main 8607 -- reaped 1 at Tue Sep 16 02:17:54 2003 reaped 1Erro was No child processes %! So it looks like the parent got killed on that error No child process This code works
(please trim your followups!) Re: mod_perl v2 Forking
whoah! people, please trim the irrelevant stuff in your replies, this thread keeps on growing for no reason. Perhaps you should read http://perl.apache.org/maillist/email-etiquette.html#Extracts_From_Other_Posts if you are new to this list. We want these threads to be useful for those who will later read them in archives. Thank you! __ Stas BekmanJAm_pH -- Just Another mod_perl Hacker http://stason.org/ mod_perl Guide --- http://perl.apache.org mailto:[EMAIL PROTECTED] http://use.perl.org http://apacheweek.com http://modperlbook.org http://apache.org http://ticketmaster.com
Re: mod_perl v2 Forking
Cameron, Have you tried issuing the command to `at`? If you don't need to interact wih the report generator, and can pass all the parameters in the command line or via a tmp file, this is a great solution. at (and the corresponding atd) will preserve your environment vars and other niceties. regards, martin
Re: mod_perl v2 Forking
I've been following this just at a high level, so if I'm posting a method that you've already tried and dismissed please forgive me. You can try forking followed by separating from the parent session. I think that will help keep your program from getting killed when apache is restarted or stopped. use POSIX; # FORK $pid = fork; if (not defined $pid) { # unable to fork } elsif ($pid) { # parent to exit, child continue exit 0; } # Separate from parent $status = 0; POSIX::setsid() or $status = Couldn't start new session: $!; if ($status) { # unable to separate from parent session } else { # searated from parent $status = 0; } On Fri, 12 Sep 2003, Cameron B. Prince wrote: Hi all... Sorry about the previous message getting screwed up... Not sure what happened... I have a report generator program written in Perl that I need to start from a CGI. The program takes about 15 minutes to run, so I must fork or double fork. I have two goals: 1) Have no zombies when the program completes 2) Fork in such a way that restarting Apache doesn't kill the forked process. I tried out the code here which is for mod_perl v1: http://perl.apache.org/docs/1.0/guide/performance.html#Forking_and_Executing _Subprocesses_from_mod_perl There are two problems with the code listed in the example: 1) Apache::SubProcess doesn't seem to contain the same methods as the older version. 2) open isn't working. (I've already been down this road and switched another call to an external program to use IPC::Run, but that program doesn't take long and needs no fork.) I took out the parts of the code that caused problems and ended up with this: $SIG{CHLD} = 'IGNORE'; defined (my $pid = fork) or die Cannot fork: $!\n; unless ($pid) { exec $command; CORE::exit(0); } This works and accomplishes my first goal, but not the second. If I start the program and restart Apache, the program is killed. Does anyone have ideas as to how to solve this? Thanks, Cameron