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

Hi,

I'm running a site which uses a script with some pretty heavy processing to do on user input, to generate a new page. This means that the user has to wait a long time for the next page, which is not good.

I have redesigned the script to update a database then go to the previously printed version of the page, which is instant, but doesnot contain the changes. That's okay because it frees them up to carry on working. My question is how can I action a script to create a new page in the background so that the next time the user inputs, the new page is ready to view?

I am currently doing this by cron but I would prefer the update to be actioned by the user during the use of the script, on the basis that the update script is 'pinged' but operates independently so the user can go ahead with the next task, without being delayed by the processing.

I'd be interested in the thoughts anyone might have to action this.

Replies are listed 'Best First'.
Re: calling one cgi script from another
by jimt (Chaplain) on Feb 20, 2007 at 17:38 UTC

    fork is your friend. Fork off a copy of your script and have it do whatever it needs to do. A fork + exec may be better, if you want to do something else in its place.

    Caveat - if you're running in a mod_perl environment, you're gonna fork your entire apache process, which has memory overhead concerns among other issues that I always seem to forget. Filehandles, is it? Only do it here if you absolutely have to. CGIs? No sweat.

    From there, just proceed as before - refresh the user back to some other page, and when your forked process completes, give it someway to flag its being finished. Touch a file, update a row in a database, something. Something that can be a quick and simple check for the front end to do.

    To show the user the changes, there are several approaches - have 'em constantly click a button ("Am I done yet?") to refresh the page and display results if appropriate. Or bring up a "loading..." screen that watches for the update and refreshes when it gets it (note that this blocks the user), or do something fancy and ajaxy that autorefreshes (or gives a refresh button) when the data is actually there.

      OK, I'l give that a try. Thanks for your help. (I don't usually accept being told to fork off, but I suppose this time it's ok!!)
      I've been reading up on this and have implemented the fork:
      if ($pid = fork) { print "I am parent\n"; } elsif (defined $pid) { print "I am child\n"; sleep 5; print "Child is done\n"; } else { die "Major error: $!"; } print "PID: $$\n";
      However I need the child to run in the background, for the browser to be freed up on printing the parent. Can anyone point me in the right direction, please?
Re: calling one cgi script from another
by GrandFather (Saint) on Feb 20, 2007 at 20:04 UTC
Re: calling one cgi script from another
by varian (Chaplain) on Feb 21, 2007 at 08:15 UTC
    The Ajax protocol has been developed to facilitate exactly this and other asynchronous HTTP transactions in a convenient way. See Perl module CGI::Ajax for support of Ajax in Perl.
Re: calling one cgi script from another
by coontie (Sexton) on Feb 20, 2007 at 19:32 UTC
    Another thing to do would be to run the script once, prepping the page. Then have the script check the timestamp of the latest run and if it's let's say under 5 mins, then present the cached version. If it's older than 5 mins, fetch the stuff from the DB. Also, if 1 guy clicked on it then the 2nd guy will benefit from the 1st guy's request, instantly.