Re: Apache2::SubProcess subprocess not subprocessing properly
Tosh Cooey <[email protected]>
| Newsgroups | gmane.comp.apache.mod-perl |
|---|---|
| Organization | Twelve Hundred Group LLC |
| Message-ID | <[email protected]> |
You aren't going to like this, and maybe what you're doing is for a
really complex situation, but it really shouldn't be so complex to just
spawn off a long running process that you don't care to ever hear back
from, honestly.
Tosh
Torsten Förtsch wrote:
> Tosh,
>
> On Tuesday 09 February 2010 14:21:57 Tosh Cooey wrote:
>> Hi after much trial and all error I am seeing that the browser
>> connection closing is also stopping my subprocess.
>>
>
> I don't know what you are trying to achieve and I don't use
> Apache2::Subprocess much. What I do to fork off processes instead is this:
>
> my $close_fd=sub {
> use POSIX ();
> my %save=(2=>1); # keep STDERR
> undef @save{@_} if( @_ );
> opendir my $d, "/proc/self/fd" or do {
> warn "Cannot open directory /proc/self/fd: $!\n";
> POSIX::_exit -1; # try this first to avoid buffer flushing
> CORE::exit -1;
> };
>
> while (defined(my $fd=readdir $d)) {
> next unless $fd=~/^\d+$/;
> POSIX::close $fd unless exists $save{$fd};
> }
> };
>
> my $spawn=sub {
> use POSIX ();
> my ($daemon_should_survive_apache_restart, @args)=@_;
>
> local $SIG{CHLD}='IGNORE';
> my $pid;
> # yes, even fork can fail
> select undef, undef, undef, .1 while( !defined($pid=fork) );
> unless( $pid ) { # child
> # 2nd fork to cut parent relationship with a mod_perl apache
> select undef, undef, undef, .1 while( !defined($pid=fork) );
> if( $pid ) {
> POSIX::_exit 0;
> CORE::exit 0;
> } else {
> if( ref($daemon_should_survive_apache_restart) ) {
> $close_fd->($daemon_should_survive_apache_restart->{fd});
> POSIX::setsid if( $daemon_should_survive_apache_restart->{survive} );
> } else {
> $close_fd->();
> POSIX::setsid if( $daemon_should_survive_apache_restart );
> }
>
> if( 'CODE' eq ref $args[0] ) {
> my $f=shift @args;
> # TODO: restore %ENV and exit() behavior
> eval {$f->(@args)};
> CORE::exit 0;
> } else {
> {exec @args;} # extra block to suppress a warning
> POSIX::_exit -1;
> CORE::exit -1;
> }
> }
> }
> waitpid $pid, 0; # avoid a zombie on some OS
> };
>
> And this is how to use it:
>
> $spawn->({survive=>1}, sub {
> my ($n, $sleep)=@_;
> for(1..$n) {
> warn "sleeping $sleep\n";
> sleep $sleep;
> }
> warn "Done\n";
> }, 10, 2 );
>
> or
>
> $spawn->
> (undef, # don't survive apache stop
> qw/bash -c/,'for (( i=0; i<10; i++ )); do echo "opi" >&2; sleep 2; done')
>
> The first argument to $spawn is an options hash with 2 possible options:
>
> survive=>BOOLEAN # should the subprocess survive an apache stop or not
> fd=>\@list_of_open_file_descriptors_to_preserve
>
> Normally the $spawn will close all files save for STDERR. With the fd option
> one can preserve other files such as database connections or other.
>
> With the survive option true the child process will be the leader of a new
> process group.
>
> NOTES:
>
> - The $close_fd function is Linux-specific. I couldn't think of a really
> portable (at least across UNICES) way to get all open file descriptors of the
> current process.
>
> - The waitpid at the end of $spawn is not necessary under Linux since
> $SIG{CHLD}='IGNORE' already takes care of zombies. But other systems need it.
>
> - Keep in mind that %ENV and exit() work different under mod_perl. If you pass
> a subroutine this behavior remains.
>
> Torsten
>
--
McIntosh Cooey - Twelve Hundred Group LLC - http://www.1200group.com/