http://www.perlmonks.org?node_id=647516

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

Hi Monks,

I know it's Friday but I hope there is someone out there can help me with my situation. I have a cgi file that needs to execute another file without having the browser wait for the outcome of the execution. Here is a little diagram:
browser->request->cgi->execute another program
                    |
                  return submitted successful message and 
                  close connection without waiting for the                 
                  other process

The code that I have is not working like the way I want because when I make the request to the cgi file, the browser waits for all processes to finish before closing the connection. I just need to execute "launch" and I do not need it to wait for it to finish before sending back the "successful submit" message. I think I am really close and this will probably involve forking and the use of exec() or even system() but this is what I have so far:

I have edited the code according to runrig's suggestion but I'm not sure if I did it right.
chdir '/' or die "Can't chdir to /: $!"; open STDIN, '/dev/null' or die "Can't read /dev/null: $!"; open STDOUT, '>/dev/null' or die "Can't write to /dev/null: $!"; my $pid = fork(); if (not defined $pid) { print "resources not available.\n"; } elsif ($pid == 0) { #this is where I launch the other executable system("/usr/local/bin/launch myfile &") or die("Cannot execute la +unch: $!\n"); exit; } else { setsid or die "Can't start a new session: $!"; open STDERR, '>&STDOUT' or die "Can't dup stdout: $!"; #this is the return message print "Your file has been sent successfully. You will be notified + via email once it has been completed. Thank you."; print end_html(); exit; }

Any suggestions would be greatly appreciated. Thanks in advance.

newb

Replies are listed 'Best First'.
Re: Fork() and exec()
by graff (Chancellor) on Oct 27, 2007 at 00:27 UTC
    You're sort of close -- you just have some confusion about which things should be done by the child as opposed to being done by the parent.

    The section of the perlipc manual pointed to by runrig above is for a slightly different situation: starting a perl script as a "daemon" process that is supposed to run continuously, operating as a service that other processes can connect to (usually via sockets) for transactions.

    In your case, I would assume that the process to be launched will accomplish some particular task and then exit (go away) when it's done. So a lot of the care and special steps involved in "daemonizing" a process would probably not apply here, or would be applied differently.

    For example, you might want STDOUT and/or STDERR for the child process to be redirected to a log file somewhere, and chdir "/" might be unnecessary or inappropriate.

    In any case, you do not want to redirect STDOUT or STDERR in the parent: STDOUT needs to go back to the web client, and STDERR should go to the web server's error log. Also, since you are doing a "fork", the child should do an "exec" -- something like this, most likely:

    my $pid = fork(); my $report; if (not defined $pid) { $report = "We were unable to process your file.\n"; warn "$0: $!\n"; # put something in the web server errlog } elsif ($pid == 0) { # child process: launch the other executable open STDOUT, ">>", "/some/path/myfile.log"; open STDERR, ">>", "/some/path/myfile.err"; exec("/usr/local/bin/launch myfile"); } else { # parent process: report the child process was launched $report = "Your file has been sent successfully. You will be noti +fied via email once it has been completed. Thank you."; } print $report, end_html();
    (I haven't tested that, but I'm pretty sure when "exec" invokes the process that you pass to it, that process inherits the current STDOUT and STDERR.)
Re: Fork() and exec()
by runrig (Abbot) on Oct 26, 2007 at 23:01 UTC
Re: Fork() and exec()
by tuxz0r (Pilgrim) on Oct 27, 2007 at 00:39 UTC
    I think the first commenter is on track here. You may, but not necesarily, run into problems fork'ing a process from a CGI script which is run by the web server user. Depends on the web server setup and could open you up to some security risks. The best idea for processing requests that don't have to happen in realtime after the user submits is to store those requests somewhere and have another program process them at regular intervals.

    I'm not sure what sort of requests you're processing, but you could put them in a flat file database in some directory and have another program run from cron at regular intervals that processes those requests and removes them from the flat file. The only issue you'd have to deal with in this situation is contention for the file resource when the CGI program is "writing" to the flat file at the same time the cron'd process wants to read from it. But you can use file locking to handle this, as it shouldn't take long to process simple requests from a text file.

    If you can give us some more details about what sort of processing is going on there might be other solutions, too.

    ---
    echo S 1 [ Y V U | perl -ane 'print reverse map { $_ = chr(ord($_)-1) } @F;'

Re: Fork() and exec()
by axl163 (Scribe) on Oct 27, 2007 at 00:57 UTC
    Thanks for the suggestion Graff. I tested out your code and the browser is still waiting for the launch process to end for some reason. For some strange reason the return message was blank which means that the script never ran through the else statement. I really appreciate your time in help me. I am definitely learning a lot here.
Re: Fork() and exec()
by axl163 (Scribe) on Oct 27, 2007 at 01:00 UTC
    I think the cron idea is a great one as it does alleviate the security risk. It is my last and only option. Thanks for all your help on this. I have been trying for 2 days straight now...
Re: Fork() and exec()
by neversaint (Deacon) on Oct 27, 2007 at 14:48 UTC
    Maybe Acme::Spork can help you.

    ---
    neversaint and everlastingly indebted.......