Login | Register For Free | Help
Search for: (Advanced)

Mailing List Archive: ModPerl: ModPerl

Apache2::SubProcess sucks

 

 

ModPerl modperl RSS feed   Index | Next | Previous | View Threaded


tosh at 1200group

Feb 19, 2010, 1:52 PM

Post #1 of 11 (1126 views)
Permalink
Apache2::SubProcess sucks

Seriously, you know what, the code below doesn't even work.

And if I get rid of the redirect and replace it with some nice pretty text:

print "Content-type: text/html\n\nTesting";

You know what? The warning for 1 (from the 'for' loop) is printed and
then it all stops, probably as the browser connection "closes".

Hiding it behind more forks made it work once but then never again.

So it is my belief that Apache2::SubProcess sucks dirty things, and that
belief won't change until I see proof to the contrary.

On a related note, anyone have tips for avoiding zombies in CGI forking?

Tosh



Tosh Cooey wrote:
> Hi after much trial and all error I am seeing that the browser
> connection closing is also stopping my subprocess.
>
> The main ModPerl::Registry program looks like this:
> ### file.pl ###
> use Apache2::SubProcess ();
> use JSON();
>
> &main(shift);
>
> sub main {
> my $r = shift;
> ...
> $r->spawn_proc_prog ('/web/html/file_fork.pl', \@argv);
> return print $cgi->redirect('index.pl');
> }
> ###
>
> And
>
> ### file_fork.pl ###
> use JSON();
> use warnings;
> use POSIX 'setsid';
> chdir '/' or die "Can't chdir to /: $!";
> open STDIN, '/dev/null' or die "Can't read /dev/null: $!";
> open STDOUT, '+>>', '/tmp/debug.txt' or die "Can't write to
> /tmp/debug.txt: $!";
> open STDERR, '>&STDOUT' or die "Can't dup stdout: $!";
> setsid or die "Can't start a new session: $!";
>
> # run your code here or call exec to another program
> foreach my $num (1..10) {
> warn $num;
> sleep(1);
> }
> ###
>
> When file.pl is executed it calls file_fork.pl and file_fork starts to
> print 1, 2, 3 and then stops around 2 or 3 depending on how long my
> browser is connected.
>
> Are there any glaring errors that anyone sees? It should work shouldn't
> it, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 after 10 seconds...
>
> Thank-you all!
>
> Tosh
>
>

--
McIntosh Cooey - Twelve Hundred Group LLC - http://www.1200group.com/


fred at redhotpenguin

Feb 19, 2010, 2:20 PM

Post #2 of 11 (1083 views)
Permalink
Re: Apache2::SubProcess sucks [In reply to]

I haven't been following this thread too closely, but is there a
reason you aren't using PerlHandlers instead of ModPerl::Registry?
MP::R is meant mostly for CGI migration, so it is probably not widely
tested with Apache2::SubProcess calls. I'd suggest trying your
external call under a PerlHandler instead and see if that works.

On Fri, Feb 19, 2010 at 1:52 PM, Tosh Cooey <tosh [at] 1200group> wrote:
> Seriously, you know what, the code below doesn't even work.
>
> And if I get rid of the redirect and replace it with some nice pretty text:
>
> print "Content-type: text/html\n\nTesting";
>
> You know what?  The warning for 1 (from the 'for' loop) is printed and then
> it all stops, probably as the browser connection "closes".
>
> Hiding it behind more forks made it work once but then never again.
>
> So it is my belief that Apache2::SubProcess sucks dirty things, and that
> belief won't change until I see proof to the contrary.
>
> On a related note, anyone have tips for avoiding zombies in CGI forking?
>
> Tosh
>
>
>
> Tosh Cooey wrote:
>>
>> Hi after much trial and all error I am seeing that the browser connection
>> closing is also stopping my subprocess.
>>
>> The main ModPerl::Registry program looks like this:
>> ### file.pl ###
>> use Apache2::SubProcess ();
>> use JSON();
>>
>> &main(shift);
>>
>> sub main {
>>  my $r = shift;
>>  ...
>>  $r->spawn_proc_prog ('/web/html/file_fork.pl', \@argv);
>>  return print $cgi->redirect('index.pl');
>> }
>> ###
>>
>> And
>>
>> ### file_fork.pl ###
>> use JSON();
>> use warnings;
>> use POSIX 'setsid';
>> chdir '/'                or die "Can't chdir to /: $!";
>> open STDIN, '/dev/null'  or die "Can't read /dev/null: $!";
>> open STDOUT, '+>>', '/tmp/debug.txt' or die "Can't write to
>> /tmp/debug.txt: $!";
>> open STDERR, '>&STDOUT'  or die "Can't dup stdout: $!";
>> setsid or die "Can't start a new session: $!";
>>
>>  # run your code here or call exec to another program
>> foreach my $num (1..10) {
>>  warn $num;
>>  sleep(1);
>> }
>> ###
>>
>> When file.pl is executed it calls file_fork.pl and file_fork starts to
>> print 1, 2, 3 and then stops around 2 or 3 depending on how long my browser
>> is connected.
>>
>> Are there any glaring errors that anyone sees?  It should work shouldn't
>> it, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 after 10 seconds...
>>
>> Thank-you all!
>>
>> Tosh
>>
>>
>
> --
> McIntosh Cooey - Twelve Hundred Group LLC - http://www.1200group.com/
>


tosh at 1200group

Feb 20, 2010, 7:01 AM

Post #3 of 11 (1076 views)
Permalink
Re: Apache2::SubProcess sucks [In reply to]

Maybe it does or doesn't work under MP::R, the answer to that is perhaps
individual.

Anyway, the solution, at least so far until I run into other problems,
seems to be to just make a system() call and the called program uses
Proc::Daemon and things *seem* to work fine in testing, we'll see when
it hits production...

Tosh



Fred Moyer wrote:
> I haven't been following this thread too closely, but is there a
> reason you aren't using PerlHandlers instead of ModPerl::Registry?
> MP::R is meant mostly for CGI migration, so it is probably not widely
> tested with Apache2::SubProcess calls. I'd suggest trying your
> external call under a PerlHandler instead and see if that works.
>
> On Fri, Feb 19, 2010 at 1:52 PM, Tosh Cooey <tosh [at] 1200group> wrote:
>> Seriously, you know what, the code below doesn't even work.
>>
>> And if I get rid of the redirect and replace it with some nice pretty text:
>>
>> print "Content-type: text/html\n\nTesting";
>>
>> You know what? The warning for 1 (from the 'for' loop) is printed and then
>> it all stops, probably as the browser connection "closes".
>>
>> Hiding it behind more forks made it work once but then never again.
>>
>> So it is my belief that Apache2::SubProcess sucks dirty things, and that
>> belief won't change until I see proof to the contrary.
>>
>> On a related note, anyone have tips for avoiding zombies in CGI forking?
>>
>> Tosh
>>
>>
>>
>> Tosh Cooey wrote:
>>> Hi after much trial and all error I am seeing that the browser connection
>>> closing is also stopping my subprocess.
>>>
>>> The main ModPerl::Registry program looks like this:
>>> ### file.pl ###
>>> use Apache2::SubProcess ();
>>> use JSON();
>>>
>>> &main(shift);
>>>
>>> sub main {
>>> my $r = shift;
>>> ...
>>> $r->spawn_proc_prog ('/web/html/file_fork.pl', \@argv);
>>> return print $cgi->redirect('index.pl');
>>> }
>>> ###
>>>
>>> And
>>>
>>> ### file_fork.pl ###
>>> use JSON();
>>> use warnings;
>>> use POSIX 'setsid';
>>> chdir '/' or die "Can't chdir to /: $!";
>>> open STDIN, '/dev/null' or die "Can't read /dev/null: $!";
>>> open STDOUT, '+>>', '/tmp/debug.txt' or die "Can't write to
>>> /tmp/debug.txt: $!";
>>> open STDERR, '>&STDOUT' or die "Can't dup stdout: $!";
>>> setsid or die "Can't start a new session: $!";
>>>
>>> # run your code here or call exec to another program
>>> foreach my $num (1..10) {
>>> warn $num;
>>> sleep(1);
>>> }
>>> ###
>>>
>>> When file.pl is executed it calls file_fork.pl and file_fork starts to
>>> print 1, 2, 3 and then stops around 2 or 3 depending on how long my browser
>>> is connected.
>>>
>>> Are there any glaring errors that anyone sees? It should work shouldn't
>>> it, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 after 10 seconds...
>>>
>>> Thank-you all!
>>>
>>> Tosh
>>>
>>>
>> --
>> McIntosh Cooey - Twelve Hundred Group LLC - http://www.1200group.com/
>>
>

--
McIntosh Cooey - Twelve Hundred Group LLC - http://www.1200group.com/


mackenna at animalhead

Feb 20, 2010, 9:33 AM

Post #4 of 11 (1084 views)
Permalink
Re: Apache2::SubProcess sucks [In reply to]

On Feb 20, 2010, at 7:01 AM, Tosh Cooey wrote:

> Anyway, the solution, at least so far until I run into other
> problems, seems to be to just make a system() call and the called
> program uses Proc::Daemon and things *seem* to work fine in
> testing, we'll see when it hits production...
>
> Tosh
>
Doesn't a process that calls 'system' wait for the child
process to complete? If the parent process is an Apache
child, is that in keeping with what you're trying to do?

cmac


tosh at 1200group

Feb 20, 2010, 10:25 AM

Post #5 of 11 (1081 views)
Permalink
Re: Apache2::SubProcess sucks [In reply to]

It does, but Proc::Daemon closes a billion file handles and sets new
process IDs and forks and forks and maybe forks a couple more times for
good measure... Fingers crossed!

I do enjoy the fact that nobody really seems to have a simple definitive
vanilla fork/spawn process down pat, it seems everyone does what I do,
trying this and that stumbling about until they come up with some
monstrosity like Torsen has that works under the sheer weight of tricks.

Tosh


mackenna [at] animalhead wrote:
> On Feb 20, 2010, at 7:01 AM, Tosh Cooey wrote:
>
>> Anyway, the solution, at least so far until I run into other problems,
>> seems to be to just make a system() call and the called program uses
>> Proc::Daemon and things *seem* to work fine in testing, we'll see when
>> it hits production...
>>
>> Tosh
>>
> Doesn't a process that calls 'system' wait for the child
> process to complete? If the parent process is an Apache
> child, is that in keeping with what you're trying to do?
>
> cmac
>
>

--
McIntosh Cooey - Twelve Hundred Group LLC - http://www.1200group.com/


torsten.foertsch at gmx

Feb 20, 2010, 12:16 PM

Post #6 of 11 (1077 views)
Permalink
Re: Apache2::SubProcess sucks [In reply to]

On Saturday 20 February 2010 19:25:39 Tosh Cooey wrote:
> I do enjoy the fact that nobody really seems to have a simple definitive
> vanilla fork/spawn process down pat, it seems everyone does what I do,
> trying this and that stumbling about until they come up with some
> monstrosity like Torsen has that works under the sheer weight of tricks.
>
Well, if I'd said: "Tosh take ModPerl::Something from CPAN and call
ModPerl::Something::spawn" you'd liked it (no matter what it does internally),
right?

That sheer weight of tricks comes down to 3 points:

- you have to close the client socket in the child process or the browser will
wait for more data

- if your process should survive an apache restart it must create its own
process group, hence the setsid().

- accidental leaking file descriptors to child processes is generally
considered a security hole

This is what my function does, it closes all file descriptors except for
STDERR and calls setsid, nothing special. Perhaps it would be good to reopen
STDIN and STDOUT as /dev/null because many programs don't like closed
STDIN/STDOUT but again, no tricks.

A tricky part would be to really restore the normal Perl environment if you
don't want to exec() another program but simply to call a Perl function.
Reverting the effect of *CORE::GLOBAL::exit=\&ModPerl::Util::exit in an
already compiled function, that is tricky. Or reestablish the connection
between %ENV and C-level char *environ[].

Torsten


cosimo at streppone

Feb 20, 2010, 12:24 PM

Post #7 of 11 (1076 views)
Permalink
Re: Apache2::SubProcess sucks [In reply to]

In data 20 febbraio 2010 alle ore 21:16:22, Torsten Förtsch
<torsten.foertsch [at] gmx> ha scritto:

> On Saturday 20 February 2010 19:25:39 Tosh Cooey wrote:
>> I do enjoy the fact that nobody really seems to have a simple definitive
>> vanilla fork/spawn process down pat, it seems everyone does what I do,
>> trying this and that stumbling about until they come up with some
>> monstrosity like Torsen has that works under the sheer weight of tricks.
>>
> Well, if I'd said: "Tosh take ModPerl::Something from CPAN and call
> ModPerl::Something::spawn" you'd liked it (no matter what it does
> internally), right?
>
> That sheer weight of tricks comes down to 3 points:
> [...]

That's really valuable, thanks for sharing.
However, a question:

is this something that should be included in Apache2::SubProcess
to make it better? Or is this something that could be published
another, separate, CPAN distribution?
Or maybe it's already out there?

--
Cosimo


torsten.foertsch at gmx

Feb 20, 2010, 1:10 PM

Post #8 of 11 (1075 views)
Permalink
Re: Apache2::SubProcess sucks [In reply to]

On Saturday 20 February 2010 21:24:31 Cosimo Streppone wrote:
> That's really valuable, thanks for sharing.
> However, a question:
>
> is this something that should be included in Apache2::SubProcess
> to make it better? Or is this something that could be published
> another, separate, CPAN distribution?
> Or maybe it's already out there?
>
Apache2::SubProcess' purpose is more for creating processes similar to CGI-
scripts. A CGI-script is killed by apache if it does not produce output for a
certain period of time. Also, the process gets killed I think at the end of
the request.

I think it could be an Apache2::SubProcess extension. That would mean adding
the stuff to xs/Apache2/SubProcess/SubProcess_pm in the source tree. But there
are a few things that are unsolved:

- is there a portable way to get all open file descriptors of the current
process? Under Linux one can readdir(/proc/self/fd). On Darwin I once simply
closed all fds from 0 to 1000. Some systems have getdtablesize(2), sometimes
it is getrlimit. Sometimes you can open /dev/something or /proc/self/something
and read the descriptor table at a certain offset. What the module should do
on Windows I simply don't know.

If you can solve this problem with apr-functions I think the it can really be
in Apache2::SubProcess.

- a way of really restoring the perl environment would be good, so that you
really can fork off subroutines.

But the real reason why it is not shaped out as a separate module yet is that
the code is really old and quite seldom needed. The main part was written
around year 2000 for mp1. At that time I didn't know about POSIX::close and
thus invented my own version like:

sub SYS_close {6;} # works on Linux and Darwin
sub sysclose {
syscall &SYS_close, shift()+0;
}

In short, the code was ugly.

And because my solution is Linux-only.

Torsten


jmccarre at akamai

Feb 20, 2010, 1:24 PM

Post #9 of 11 (1076 views)
Permalink
Re: Apache2::SubProcess sucks [In reply to]

re: close all open file descriptors portably

well, if one is on a POSIX system, _SC_OPEN_MAX gives the max integer.
Then just close them all.
Here's my usual recipe for this:

# close all open file descriptors
my $max_fd = POSIX::sysconf(&POSIX::_SC_OPEN_MAX);
$max_fd = ((! defined $max_fd) || $max_fd < 0) ? 64 : $max_fd;
while (--$max_fd >= 0) {
next if ($max_fd == fileno($pid_fh));
POSIX::close($max_fd);
}

# now reopen std{in,out,err} on /dev/null
open(STDIN, "+>/dev/null");
open(STDOUT, "+>&STDIN");
open(STDERR, "+>&STDIN");

Proc::Daemon does the same thing...

HTH,
-- jeff


On 2/20/10 1:10 PM, "Torsten Förtsch" <torsten.foertsch [at] gmx> wrote:

> - is there a portable way to get all open file descriptors of the current
> process? Under Linux one can readdir(/proc/self/fd). On Darwin I once simply


sgifford at suspectclass

Feb 20, 2010, 1:48 PM

Post #10 of 11 (1074 views)
Permalink
Re: Apache2::SubProcess sucks [In reply to]

2010/2/20 Torsten Förtsch <torsten.foertsch [at] gmx>
[ ... ]

> - is there a portable way to get all open file descriptors of the current
> process? Under Linux one can readdir(/proc/self/fd). On Darwin I once
> simply
> closed all fds from 0 to 1000. Some systems have getdtablesize(2),
> sometimes
> it is getrlimit. Sometimes you can open /dev/something or
> /proc/self/something
> and read the descriptor table at a certain offset. What the module should
> do
> on Windows I simply don't know.
>

I think just closing stdin and stdout is likely to be enough, or maybe all
file descriptors from 0 to $^F . The OS will close any others that have the
close-on-exec bit set, and the close-on-exec bit is set by default by Perl's
open function. Anybody setting this to something different probably
understands the consequences.

----Scott.


tosh at 1200group

Feb 21, 2010, 8:02 AM

Post #11 of 11 (1070 views)
Permalink
Re: Apache2::SubProcess sucks [In reply to]

Hey Torsten, I hope you don't think I was disparaging (
http://dict.leo.org/?lang=en&lp=ende&search=disparaging ) your help, I
certainly wasn't and I want to thank you for it. I was just lamenting
on a lack of a clear simple example to use as a starting point, much
like almost every programming language starts out with "Hello World" in
the first chapter.

So yes, install ModPerl::Something and then use
ModPerl::Something::Spawn would be great, and it could even come with
some caveats on how leaving it like that could cause problems, and then
people could use that as a starting point.

Anyway, I'm just waiting for a couple days with my simple solution in
production to see if it causes any problems and then I'll post it here
and try to get something that could be such a starting point.

Tosh



Torsten Förtsch wrote:
> On Saturday 20 February 2010 19:25:39 Tosh Cooey wrote:
>> I do enjoy the fact that nobody really seems to have a simple definitive
>> vanilla fork/spawn process down pat, it seems everyone does what I do,
>> trying this and that stumbling about until they come up with some
>> monstrosity like Torsen has that works under the sheer weight of tricks.
>>
> Well, if I'd said: "Tosh take ModPerl::Something from CPAN and call
> ModPerl::Something::spawn" you'd liked it (no matter what it does internally),
> right?
>
> That sheer weight of tricks comes down to 3 points:
>
> - you have to close the client socket in the child process or the browser will
> wait for more data
>
> - if your process should survive an apache restart it must create its own
> process group, hence the setsid().
>
> - accidental leaking file descriptors to child processes is generally
> considered a security hole
>
> This is what my function does, it closes all file descriptors except for
> STDERR and calls setsid, nothing special. Perhaps it would be good to reopen
> STDIN and STDOUT as /dev/null because many programs don't like closed
> STDIN/STDOUT but again, no tricks.
>
> A tricky part would be to really restore the normal Perl environment if you
> don't want to exec() another program but simply to call a Perl function.
> Reverting the effect of *CORE::GLOBAL::exit=\&ModPerl::Util::exit in an
> already compiled function, that is tricky. Or reestablish the connection
> between %ENV and C-level char *environ[].
>
> Torsten
>

--
McIntosh Cooey - Twelve Hundred Group LLC - http://www.1200group.com/

ModPerl modperl RSS feed   Index | Next | Previous | View Threaded
 
 


Interested in having your list archived? Contact Gossamer Threads
 
  Web Applications & Managed Hosting Powered by Gossamer Threads Inc.