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 @sa...@_} 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/