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

I'm really hoping someone can shed some light on this problem.

I have a cgi script run from a web browser which should allow the user to start a background process. The background process will run indefinitely (it's responsible for detecting files and processing them, sleeping for a period of time then starting over again) so i want to be able to start the process with no waits and return control to the cgi script.

I've tried system("perl script.pl &"), fork/exec "perl script.pl" and open (CMDLOG,"| $cmd") all to no avail. They all run the script okay but they all wait for it to complete before returning control to parent cgi.

By the way this is all running under Linux if that has any bearing.

Any suggestions would be greatly appreciated. I'd prefer to use core Perl functionality if at all possible. Use of anything else would require approval which i really need to avoid. Thanks, M.

Replies are listed 'Best First'.
Re: fork/exe, system open etc.
by moritz (Cardinal) on May 02, 2008 at 12:57 UTC
Re: fork/exe, system open etc.
by zentara (Cardinal) on May 02, 2008 at 13:25 UTC
Re: fork/exe, system open etc.
by mscharrer (Hermit) on May 02, 2008 at 13:19 UTC
    fork should be the way to do it.
    E.g. you can detach normal command line scripts from the terminal and so let them run in the background by using:

    fork && exit;

    Because fork returns the child PID (>0) to the parent and 0 to the child it can be used as a boolean.
    As similar code should work for you. Did you tried to set $SIG{CHLD} = 'IGNORE';?

    AFIK exec replaces the perl interpreter process with the called command - that's not what you want.

Re: fork/exe, system open etc.
by almut (Canon) on May 02, 2008 at 13:54 UTC

    One sometimes overlooked detail is that you need to close the STDOUT/STDERR handles in the child process for the parent to continue and finish its job normally. (Or better yet, reopen them to some logfile...)

      I think this cuts to the heart of the matter. It's not that your parent is waiting for the child to finish, but that the Apache server is waiting for the output pipe from the CGI script to close, and the child process still has it open. Closing STDOUT in the child should fix the problem. Try one of these:
      system("perl script.pl >/dev/null &"); open(CMD, "|perl script.pl > /dev/null");

      To illustrate that both the system and open methods will spawn a child process without blocking the parent, both of these scripts will continue to print "boo" even after the parent has exited:

      system("while true; do echo boo; sleep 2; done &"); print "system done - exiting\n";
      open(CMD, "|while true; do echo boo; sleep 2; done"); print "open returned - exiting\n";
        It's not that your parent is waiting for the child to finish, but that the Apache server is waiting...

        You're absolutely right, I should've said grandparent (from the child's perspective)... Of course it's the Apache process which hangs waiting for the long-running process to close the pipes that were duplicated by the fork.

        Brilliant, and yet so simple. It makes me wonder why it's not discussed in any of the documentation i've read (unless, of course, i'm reading the wrong documentation). Thanks pc88mxer.