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

Hi!

I'm having a problem with system/exec, i'm hoping ya can lend me a hand...

I've got two perl scripts. Script one is browser based, takes formdata input and stores it into a local file on the server. Then it needs to execute the second script (which processes the file), display a message to the user and end the browser session (while the 2nd script is still going). The second script takes quite a while, and involves a lot of database operations, so I don't want the browser to have to wait for it to finish ( it might time-out and kill the script! XD )

From reading the man pages, I expect exec to create a new fork, start running the second script, and let the first one continue. However, exec hangs up the web browser on script execution even worse than system does!

Is my usage wrong, or does this forking not work properly in an apache/web browsing environment?

Here's the syntax I've used...


exec "/home/myuser/www/cgi-bin/foo/bar/import.pl $fn"; system "/home/myuser/www/cgi-bin/foo/bar/import.pl $fn"; exec "/home/myuser/www/cgi-bin/foo/bar/import.pl", $fn; system "/home/myuser/www/cgi-bin/foo/bar/import.pl", $fn;
Is there another way to have the browser-run perl script execute the second script, in the background, and continue without hanging?

Replies are listed 'Best First'.
Re: system or exec in a web environment
by dave_the_m (Monsignor) on Jun 09, 2004 at 09:11 UTC
    exec doesn't do a fork. You have to explicity call fork() yourself and then exec in the child. You should also close STDIN/OUT/ERR in the child before execing.

    Dave.

Re: system or exec in a web environment
by Abigail-II (Bishop) on Jun 09, 2004 at 09:12 UTC
    From reading the man pages, I expect exec to create a new fork
    Which man page did you read? The first sentence of my manpage:
    The exec function executes a system command and never returns

    Is there another way to have the browser-run perl script execute the second script, in the background, and continue without hanging?
    Fork, and in the child, first close STDOUT and STDERR (or else the webserver won't think you're done), then exec the second program.

    Abigail

Re: system or exec in a web environment
by rbi (Monk) on Jun 09, 2004 at 09:46 UTC
    I've used something like:
    my $pid; $SIG{CHLD} = sub { wait }; if ($pid = fork()) { # Master print "Process was started in background." return; } else { # Child exec "my_program"; }
Re: system or exec in a web environment
by paulbort (Hermit) on Jun 09, 2004 at 13:58 UTC
    The other monks are correct, 'exec' never returns. Never.

    I would suggest changing the CGI script to give the user a message like "Your file is being processed" and just end.

    Then in the background, you need a listener program that watches that directory for new files, picks them up in turn, and processes them. The one I wrote is a shell-script that runs a Perl script every 10 seconds, and is started by rc.local. If you want it to process multiple files at a time, a thread pool can be your friend.

    If you need to keep users informed about how their files are going, a CGI script that displays results from a status table, updated by the worker threads, might make sense. (You could even make it part of the original script with a refresh, if you want that 'interactive application' style.)

    --
    Spring: Forces, Coiled Again!