Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

Long Process Waits Until End to Display Results

by C_T (Scribe)
on Dec 07, 2004 at 17:06 UTC ( [id://412947]=perlquestion: print w/replies, xml ) Need Help??

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

I've got a CGI script which does some lengthy processing and reports the results to the user. Right now I'm doing something like this:

#===== Open I/O pipes and run the process $pid = open3(\*DEV_NULL, \*OUT, \*ERR, "$my_long_process"); #===== Print the results while (<OUT>) { $buffer .= "$_<br>"; #===== Update the display cache $cache->set($session, [0, $buffer]); }

Which works, except it waits until $my_long_process completes before it sends any output back to the browser. If my_long_process takes an hour to run, the browser sits there for an hour with no updated information.

If I run my_long_process from the command line, however, it updates as it goes, so that the user knows what's going on.

Is there a way to set open3() to an unbuffered mode so it returns what my_long_process is doing in real time instead of waiting until the end?

Failing that, is there a better way to do this long process in the fork such that I can get its results as its doing things rather than waiting until the end?

Thanks!

CT

Charles Thomas
Madison, WI

Replies are listed 'Best First'.
Re: Long Process Waits Until End to Display Results
by tilly (Archbishop) on Dec 07, 2004 at 17:13 UTC
      Someone sent me that excellent article in response to another question. The problem is not the browser timing out, but rather that the process waits until the end to display the results.

      I've actually used the exact code that's in the article you reference:

      my $command = "make -i -j 10 -f upgrade.make"; unless (open F, "-|") { open STDERR, ">&=1"; exec "$command"; } while (<F>) { $buffer .= $_; $cache->set($session, [0, $buffer]); }

      And it still waits until the process completes to give me back any output whereas if I run $command from the command line it gives me real-time feedback.

      CT

      Charles Thomas
      Madison, WI
        The problem is not the browser timing out, but rather that the process waits until the end to display the results.

        You may have a different problem, but merlyn's article is still a possible solution. Have your lengthy process fork off and write its output to a file, then have the CGI refresh every X seconds, reading that output file, and displaying the results. Perhaps you could even parse the output file and make the results a bit more user friendly (this is just speculation -- the output may already be user friendly).

        You may also find that your lengthy process buffers its output writing to the file, though. In that case, you can investigate some of the solutions sgifford recommended.

Re: Long Process Waits Until End to Display Results
by Yendor (Pilgrim) on Dec 07, 2004 at 17:37 UTC

    Have you tried setting $| = 1; at the top of your script? That sets the buffer to flush immediately, and it's a standard part of all of my CGI scripts...

Re: Long Process Waits Until End to Display Results
by sgifford (Prior) on Dec 07, 2004 at 17:42 UTC
    There are two places buffering could be happening. First, it could be in your script; I don't know what your $cache object does, but make sure whenever your actually print the output that $| is set to a true value.

    Second, it could be in the $my_long_process program. Many programs, and the default stdio library, buffer output unless it's to a tty. If that's the case with $my_long_process program, it wouldn't buffer output when you ran it from the command-line (because it was connected to a tty), but would when run from your program. You might be able to test by running:

    $my_long_program |cat
    to see if it buffers output then.

    If that's the case, finding an option to cause the program to display output immediately is the easiest solution; the other option is to connect it to a pseudo-tty, with something like Expect.

      make sure whenever your actually print the output that $| is set to a true value.

      I have done this. Like you, this is something I used in most of my scripts.

      Second, it could be in the $my_long_process program. Many programs, and the default stdio library, buffer output unless it's to a tty. If that's the case with $my_long_process program, it wouldn't buffer output when you ran it from the command-line (because it was connected to a tty), but would when run from your program. You might be able to test by running: $my_long_program |cat

      It still gave me real-time feedback when run piped into cat as you suggested.

      CT

      Charles Thomas
      Madison, WI
Select this! ;-)
by Luca Benini (Scribe) on Dec 07, 2004 at 18:10 UTC
    Have you tried to use select (2° entry) From select (2) (system call)
    select, pselect, FD_CLR, FD_ISSET, FD_SET, FD_ZERO - synchronous I/O multiplexing
    The keyword is synchronous....
      Changing the code as follows:

      unless (open F, "-|") { open STDERR, ">&=1"; select(STDIN); $| = 1; select(STDERR); # also tried select(F) here $| = 1; exec "$command"; } while (<F>) { $buffer .= $_; $cache->set($session, [0, $buffer]); }
      Does not make any difference.

      CT

      Charles Thomas
      Madison, WI
        Try with second entry.... select RBITS,WBITS,EBITS,TIMEOUT
Re: Long Process Waits Until End to Display Results
by webmite (Initiate) on Dec 08, 2004 at 14:32 UTC
    Wild guess from the side-lines
    ....
    This may be a browser issue. Typical of browsers to accept unformatted text as an entire
    block until a recognized tag is found.
    try something like ...
    $buffer .= "<div>".$_."</div>";

    Regards,
      True, but I'm throwing a <br> tag after every line, so I don't believe that's the issue.

      CT

      Charles Thomas
      Madison, WI
Re: Long Process Waits Until End to Display Results
by traveler (Parson) on Dec 07, 2004 at 23:17 UTC
    I think the issue is in the $cache->set call. What type of object is $cache? Is it possible that it is cacheing the whole output?
      I think the issue is in the $cache->set call. What type of object is $cache?

      It's a Cache::FileCache object as described in the paper by Merlyn referenced earlier in the thread.

      Basically the cgi keeps calling itself every five seconds, and when it revisits itself it prints the contents of the cache object. So I store all output of the script in this cache object.

      Once the long process completes, all its output goes into the cache object as it should. It's just that it takes until it completes to see what's going on.

      CT

      Charles Thomas
      Madison, WI
        OK. merlyn's article deals with how to save the information between invocations to a CGI (using a persistent cache and session key to get the data back). You want to do something different. You want real timeish results. That's different.

        You do not need to put the data in the cache; in fact, it is what is storing or buffering the output. You need to set $| to 1 and send the data directly to the user. One big issue, though, is that browsers sometimes "timeout": as noted above if they don't see data in n seconds, they disconnect. I have solved this in the past using timeouts. For now, I'd just write the data directly to the browser with $|=1 and without the cache, and see what happens.

        You could use a solution like merlyn's by extending the key to be $session-$line and then retreiving each line individually.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others perusing the Monastery: (3)
As of 2024-04-25 17:31 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found