Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

Detached forking in a CGI script

by xylose (Initiate)
on Apr 29, 2016 at 15:06 UTC ( [id://1161882]=perlquestion: print w/replies, xml ) Need Help??

xylose has asked for the wisdom of the Perl Monks concerning the following question:

I'm having a problem satisfying a number of constraints in a CGI script I'm writing.

I need the script to fork a child process and to get hold of the pid of this child, but to then not make the parent (the CGI process) wait for the child, and allow it to exit immediately.

One extra complication is that in the child I exec a new program (an R script), but capture STDOUT and STDERR into log files, so I can't close those filehandles before doing the exec.

I've tried a number of different approaches, but anything which gives me the pid and starts the child process correctly always makes the parent hang until the child is done.

My current (not working) best guess is:

$SIG{CHLD} = 'IGNORE'; my $pid = fork(); if ($pid) { # We're the child and we need to start the analysis # First we'll write out pid into a file in the run # folder so that the results tracker can tell if we've # died. open (PID,'>','pid.txt') or die "Failed to write to pid file : $!" +; print PID $pid; close PID or die "Failed to write to pid file: $!"; exec("Rscript analysis.r > log.txt 2>errors.txt"); exit(0); } print $q->redirect("script.cgi?job_id=$job_id");

In this version the child runs, but the parent doesn't exit until the child has completed.

Any ideas how I can have my cake and eat it?

Thanks.

Replies are listed 'Best First'.
Re: Detached forking in a CGI script
by FreeBeerReekingMonk (Deacon) on Apr 29, 2016 at 20:39 UTC
Re: Detached forking in a CGI script
by stevieb (Canon) on Apr 29, 2016 at 15:34 UTC

    I'm not sure fork is the right tool here. I recently came across an easy to use module to put things in the background, Proc::Background that may help (cross-platform even).

    use warnings; use strict; use Proc::Background; my @cmd = qw(perl sleep.pl); my $proc = Proc::Background->new(@cmd); my $pid = $proc->pid; print "*** $pid ***\n";

    Output showing parent exits while proc still running:

    ~/scratch$ perl proc.pl *** 3489 *** ~/scratch$ ps ax | grep sleep 3489 pts/1 S 0:00 perl sleep.pl

      Looking at Proc::Background, it appears to use fork and exec.

      So I would say that Fork the correct tool for the job

        Pedantic..., I'll rephrase... "this job appears much easier when using a known-working module that shadows what you want to do in the background, with a nice, clean API".

        Out of curiosity, what working suggestions do you have? ;)

Re: Detached forking in a CGI script
by flexvault (Monsignor) on Apr 29, 2016 at 18:22 UTC

    xylose,

      I need the script to fork a child process and to get hold of the pid of this child, but to then not make the parent (the CGI process) wait for the child, and allow it to exit immediately.

    A few years back and this process was easy, but today many of the web servers will not allow children to continue to run if the parent exits. I've gotten around this by using a continuous running Perl script that keeps checking a file for instructions on work to be passed to new forked script.

    The cgi script locks the file, adds the work to be done to that file, and then closes (which unlocks also) the file and exits.

    The continuous running script sees the new work and forks to do the required work. (Note: You can also use 'pre-forked' scripts to do this.)

    Possibly the referenced module does something similar and may give a more complete solution than using your own 'fork'. Just because it uses 'fork' and 'exec' doesn't mean that there isn't a whole lot more logic necessary to provide independent processes to complete the work after the parent cgi script exits. YMMV

    Regards...Ed

    "Well done is better than well said." - Benjamin Franklin

Re: Detached forking in a CGI script
by Anonymous Monk on Apr 30, 2016 at 00:21 UTC
    you have the logic of your script backwards
    my $pid = fork(); if ($pid) { # We're the child and we need to start the analysis
    fork returns 0 (zero) in the child, and non-zero (pid of the child) in the parent. Since 0 is false in Perl, if ($pid) block will be run by the parent.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1161882]
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others examining the Monastery: (3)
As of 2024-04-19 15:44 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found