?
Solved

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

Posted on 2007-09-28
7
Medium Priority
?
2,879 Views
Last Modified: 2008-01-17
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!
0
Comment
Question by:jasonsbytes
  • 4
  • 3
7 Comments
 
LVL 39

Expert Comment

by:Adam314
ID: 19979089
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.


eg:
#doing stuff....
SlowSub();
#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
    exit;
}
0
 
LVL 17

Author Comment

by:jasonsbytes
ID: 19979191
Thank you, I will give this a try today.

This is running on an IBM AIX (Unix) system.
0
 
LVL 17

Author Comment

by:jasonsbytes
ID: 19979284
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?

thx!
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 39

Expert Comment

by:Adam314
ID: 19979325
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.
0
 
LVL 17

Author Comment

by:jasonsbytes
ID: 19979344
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;
   }
   else
   {
      $msg{'TXT'} = $pid;
      return \%msg;
   }

   my $dbhP = dbconnect('scully');

   my $sql_P_edit_type = qq{
      select   type_id,
               name,
               sequence
      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(?, ?, ?, ?) };

   $dbhP->disconnect();
   exit;
}
0
 
LVL 17

Author Comment

by:jasonsbytes
ID: 19979353
That makes sense, I will use file logging or maybe use a db table...  I guess I just need help with the above now...
0
 
LVL 39

Accepted Solution

by:
Adam314 earned 2000 total points
ID: 19979372
The fork function returns the child pid to the parent process, 0 to the child process, or undef if the fork is unsuccessful.

This will cause both the parent and child to return:
    # 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;
   }
   else
   {
      $msg{'TXT'} = $pid;
      return \%msg;
   }

You probably want something like this:
    # 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;
   }
   elsif($pid)    #only parent returns
   {
      $msg{'TXT'} = $pid;
      return \%msg;
   }
    #Child continues here
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

I've just discovered very important differences between Windows an Unix formats in Perl,at least 5.xx.. MOST IMPORTANT: Use Unix file format while saving Your script. otherwise it will have ^M s or smth likely weird in the EOL, Then DO NOT use m…
Email validation in proper way is  very important validation required in any web pages. This code is self explainable except that Regular Expression which I used for pattern matching. I originally published as a thread on my website : http://www…
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…
Six Sigma Control Plans
Suggested Courses

831 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question