Link to home
Start Free TrialLog in
Avatar of Jason Minton
Jason MintonFlag for United States of America

asked on

Fork Perl CGI sub into background and wait for it to finish.

I have a Perl CGI script and I have sub that I'm calling that takes a very long time to run.  It takes so long that the web browser times out and the process dies before it finishes.

I need to fork this sub routine into the background somehow, then display a page that says something like 'processing...' and this page keeps refreshing and checking to see if the process has completed.

1. How can I push a perl subroutine into the background so it will run to completion.
2. How can I check to see if the background process has completed?
3. Need to do all of this for CGI web app.

Thank you!
Avatar of Adam314

1. You can use fork to split your process into two processes.
2. You can check the running processes to see if it is still running.  This will be OS dependent.  Which OS are you running?  You would use ps on unix.
3.  This should work within a CGI app.

#doing stuff....
#do more stuff

sub SlowSub {
    #Call fork
    my $pid=fork;
    #Display error message if not successful
    die "Could not fork: $!\n" unless defined($pid);

    #parent returns immediately
    return if $pid;

    #Only child runs here
    #Do stuff that is slow

    #Child exits
Avatar of Jason Minton


Thank you, I will give this a try today.

This is running on an IBM AIX (Unix) system.
Currently in my SlowSub I check a lot of things for errors and if it failes I return from the sub with some error code...  If I'm running SlowSub as a child process, I'm assuming I can't use return, only exit.  Is there someway I can detect that it exited due to an error instead of success?

I guess I could write some type of file somewhere and check for that, but is there a better way?

If it is possible for your SlowSub to do some error checking quickly, then you could have it only fork if thinks okay.
But the child will not be able to write to the web browser, anything it prints on STDOUT or STDERR will not be seen.  Logging to a file is the most common method.
I guess I'm doing this wrong... can you tell me?

my $forked = copyProdToDevView($p{'view_id'});

sub copyProdToDevView($)
   my $view_id = shift;

   my %msg;
   $msg{'ERR'} = 0;

   # this can take a long time, so run it as a child process
   my $pid = fork;
   if (!defined($pid))
      $msg{'ERR'} = 1;
      $msg{'TXT'} = qq{Could not create child process for data import into view. $!};
      return \%msg;
      $msg{'TXT'} = $pid;
      return \%msg;

   my $dbhP = dbconnect('scully');

   my $sql_P_edit_type = qq{
      select   type_id,
      from     ${dbtablePrefix}_ec_edit_type
      where    view_id = ? };

   my $sql_D_edit_type = qq{
      insert into ${dbtablePrefix}_ec_edit_type
      (type_id, name, sequence, view_id)
      values(?, ?, ?, ?) };

That makes sense, I will use file logging or maybe use a db table...  I guess I just need help with the above now...
Avatar of Adam314

Link to home
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial