Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

Ensuring the user doesn't have to wait for a CGI to finish

by neilwatson (Priest)
on Jul 11, 2002 at 16:25 UTC ( [id://181059]=perlquestion: print w/replies, xml ) Need Help??

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

Fellow monks,

This script may take a while to finish. I don't want the user to have to wait. This is what I had in mind:

print header, start_html, h2('Your script is now running.'), h2('I will email you the results when I am finished'); # run time consuming code here

At that point, how I free the browser and contiue running the script?

Neil Watson
watson-wilson.ca

Replies are listed 'Best First'.
•Re: Ensuring the user doesn't have to wait for a CGI to finish
by merlyn (Sage) on Jul 11, 2002 at 16:41 UTC

      I had this same problem a few months ago with a script I built for Warner Bros. The script would load 70,000 surveys, calculate statistical means and medians for each question, then output a master report. The problem was, was that the calculations were SLOW. Sometimes the CGI script took a half hour to run.

      The beta testers (heh, myself really) would hit reload after a minute or two, thinking that the script had crashed. Why no response from the server? *click* *click* The server stopped responding completely, it crashed from the concurrent requests (CPU: 14.30). That night I started looking for another job.

      Two months of work down the drain.

      After I calmed down a bit, I realized that it was okay that the request was slow to execute. That's a lot of surveys we're talking about, users just need a status screen updating them on the status of their request. That's all. No big deal. So I built a minor caching system that cached the reports, and then opened Dreamweaver and built a template. Here's a screenshot of the final status screen in action. (Note the progress bar at the bottom in HTML tables. I think it's cute.)

      Now all I had to do was send the browser a redirect to this status page (which has a meta tag requesting itself to be refreshed every 5 seconds), then periodically update it as I continued processing surveys, until I finish, and then I'll redirect it to the master report. Easy as pie. Right?

      WRONG!!!

      It worked fine in Opera and Netscape but IE wouldn't execute the redirect until AFTER the script finished running!!!! Bastard program. I knew there was a good reason to never trust IE. Evil manipulating bastards, I say. And at this point I was behind schedule, I should have delivered the application days before.

      My intuition is that Apache doesn't relinquish the TCP/IP connection (server side) until the perl process exits. That's logical right? IE received the redirect just fine, but it waited for that TCP/IP connection to drop before actually executing it. (There's even a Microsoft knowledge base article on the problem, but I switched computers and don't have it bookmarked any more.)

      I'm not a perl guru or anything, so instead of wasting more time figuring out how to tell Apache to drop the connection, and probably learning something in the process, I hacked a crappy fix together that works:

      my $pid; # # Fork the current process. # if (!defined ($pid = fork)) { DieNice("Unable to fork: $!\n"); } elsif (! $pid) { # This is the child fork, for processing. close(STDIN); close(STDOUT); close(STDERR); } else { # This is the parent fork, for the browser. print $query->redirect("http://$servername/wbnorm/cache/status.h +tml"); # Apache, you will answer to me! exit; } # # Calculations continue as normal here #

      *ding*!

      (I registered after a year of lurking just to participate in this very topic. As a new user, I'd like to say, merlyn -- you've saved my ass dozens of times, and I thank you for it.)

        ... and of course, I end up posting as anonymous monk. *doh*
Re: Ensuring the user doesn't have to wait for a CGI to finish
by tune (Curate) on Jul 11, 2002 at 16:39 UTC
    You have to add the following line at the beginning of your script:
    $|=1;
    It is setting printing into direct mode (turning buffer off), so perl will flush out everything in realtime.

    --
    tune

Re: Ensuring the user doesn't have to wait for a CGI to finish
by dws (Chancellor) on Jul 11, 2002 at 17:52 UTC
    The general problem you're facing is that of returning a response (in the form of an HTML page) to the user while work continues on the server side.

    There are a couple of strategies for this. merlyn points to one of them, which is to have the CGI fork, and continue work in the child process while the parent process exits. Works great on Unix systems, works very poorly on Win32 (IIS).

    Another approach is to write a separate server process to handle work requests. The CGI queues up a request to this new worker process, either by dropping a file into a well-known directory, or by opening a socket to it and pushing the request along. The CGI pushs and HTML page back to the browser and exits, while the worker process grinds through requests.

    This latter approach works well when you have control of the server. Some ISPs forbid running your own server processes.

      On Unix boxen you may be able to use a simple quick and dirty solution:
      open AT, "|at now" or die "Failed piping to 'at': $!"; print AT "$some $commandline $to_execute\n"; print AT "$or $maybe $two\n"; close AT
      Of course I didn't tell you that. :-)

      Makeshifts last the longest.

Re: Ensuring the user doesn't have to wait for a CGI to finish
by zentara (Archbishop) on Jul 11, 2002 at 16:40 UTC
    Redirect the browser to your homepage? or a thank-you page?
    print "Location: $return_page\n\n";

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://181059]
Approved by IlyaM
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others romping around the Monastery: (4)
As of 2024-04-19 13:10 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found