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/
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.