[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

Pause during HTML generation gives odd results

Posted on 2011-04-22
11
Medium Priority
?
229 Views
Last Modified: 2012-05-11
Hi Experts,

For technical reasons I may not have to go into, I'm pausing for 5 secs, part way through generating HTML, with Perl.  Here's a very simplied version of the code, which demonstrates the problem I'm having:
#!/usr/bin/perl

$| = 1;  # Turn off buffered output

print <<EOF;
Content-Type: text/html; charset=utf-8\n
<html>
<body>
  Before
EOF

sleep 4;

print <<EOF;
  After
</body>
</html>
EOF

Open in new window

When viewed in a browser, I would have expected that the above code would have done this:
- "Before" appears.
- A 4 sec pause.
- " After" appears.
And that's almost what happens, except the pause happens first, instead, regardless of whether I have the non-buffering line ("$| = 1;") in place.

Questions:

1. Why does the pause occur after all the text appears, instead of between the 2 words?

When I change the sleep to be 5 secs, I get even more unexpected results, as described in the following questions:

2. If the non-buffering line is included, the result is:
- A 5 sec pause.
- Then "Before Before" appears (not "Before After").
If I view Page Source in Firefox, it looks like this:
    <html>
    <body>
    Before
    <html>
    <body>
    Before

Why does this happen?

3. When I remove the non-buffering line, do I get this error:
    Internal Server Error
    The server encountered an internal error or misconfiguration and was unable to complete your request.
    Please contact the server administrator, webmaster@mydomain.com and inform them of the time the error occurred, and anything you might have done that may have caused the error.
    More information about this error may be available in the server error log.
    Additionally, a 404 Not Found error was encountered while trying to use an ErrorDocument to handle the request.
    Apache/2.0.63 (Unix) mod_ssl/2.0.63 OpenSSL/0.9.7a DAV/2 mod_auth_passthrough/2.1 mod_bwlimited/1.4 FrontPage/5.0.2.2635 Server at crs.tospeirs.net Port 80

Why does this happen?

4. How can I get around the above problems, with a 5 sec sleep in place?

The web server is run by a commerical hosting company, so I'm limited as to what changes I can make to the environment.  The control panel is cPanel.

Thanks.
0
Comment
Question by:tel2
  • 6
  • 5
11 Comments
 
LVL 27

Accepted Solution

by:
wilcoxon earned 2000 total points
ID: 35448160
1) It doesn't.  The browser will not display the page until it receives the full HTML.  The pause is occurring where you put it but that doesn't change the display.

2) That is very strange and makes no sense.  Given your code, there should never be a double Before.

3) Not sure.  I don't see any issues.

4) In order to do what you want, you need to play with the "continuation" HTTP return code (100 iirc).  What exactly can be done with it varies by browser and web server.

Generally, you should add "use strict", "use warnings", and "use CGI::Carp qw(fatalsToBrowser)" to your code.  This will help greatly with debugging and may give better error information (such as with #3).
0
 
LVL 12

Author Comment

by:tel2
ID: 35451533
Thanks for your advice, wilcoxon.

Here are my responses:

1. OK - thanks.

2. My feelings exactly.  And furthermore, if I move the "sleep 5;" to the end of the script, leaving the "$| =1;" in tact, I get this output:
   Before After Before After
And the Page Source looks like this:
    <html>
   <body>
    Before
    After
    </body>
    </html>
    <html>
    <body>
    Before
    After
    </body>
    </html>

Anyone got any ideas on why this would happen?

3. Me neither.  I've added your suggested code to the beginning, i.e.:
    use strict;
    use warnings;
    use CGI::Carp qw(fatalsToBrowser);
(which I have used in some scripts before, but hadn't bothered here), and I get exactly the same "Internal Server Error..." message.  I checked the log, as the error suggests, but that just says:
   [Sat Apr 23 00:30:59 2011] [client xxx.xx.xxx.xxx] File does not exist: /home/myname/public_html/mydir/500.shtml

4. Oh.  Is this an Apache configuration change?

My current thoughts are, I'm going to have to avoid the pause by changing my current strategy.
Unless...  Does Perl have a way of running a subroutine as a background process, or do I need to put the code in a separate script and run that in the background?  The OS is Linux, so I assume I could do something like:
    `script2.pl&`;
if I had to, but passing values would be easier if it wasn't an external script.  If I put the pause at the beginning of the subroutine I'm calling, and run that in the background, then the rest of the script won't be slowed down.  The pause seems to be required to allow an external process to keep up with my script's processing.

Thanks.
Tel2
0
 
LVL 12

Author Comment

by:tel2
ID: 35451896
Hi again wilcoxon,

I tried the same kind of thing on different webhosts (OpenHost and HD, for my own reference), and it worked fine with them.  My test was with and without the "$| = 1;" line, and with sleeps of at least 50 secs.

I'm not planning to change webhost just for this though.  Any comments on my previous post, including the background processing option?

Or is there a way to get the output to go to the browser, while the script keeps doing a bit more processing (a bit like having the sleep at the end, if you see my update to question 2, in my last post).

Thanks.
0
Get quick recovery of individual SharePoint items

Free tool – Veeam Explorer for Microsoft SharePoint, enables fast, easy restores of SharePoint sites, documents, libraries and lists — all with no agents to manage and no additional licenses to buy.

 
LVL 27

Assisted Solution

by:wilcoxon
wilcoxon earned 2000 total points
ID: 35453598
4. I believe this is the way it has always officially worked (per W3C).  If it worked for you in some other way in the past, then it was unofficial and was due to the server and/or browser.

To run something in the background within perl, check perldoc fork (it can be a little confusing at first).

Very strange behavior.  Have you asked support with your webhost why it is working that way?  You can now prove to them it is just their hosting that behaves this way.
0
 
LVL 12

Author Comment

by:tel2
ID: 35509513
Hi wilcoxon,

Thanks for your reply, and sorry for the delay in getting back to you.

Yes, I was considering taking that up with my webhost, and I finally did that yesterday, and they have "increased the Timeout value for scripts execution in Apache configuration".  Looks as if they've probably changed it from 5 to 30 secs, which is fine.

However, the above strategy still leaves my user waiting extra time for the sleep to complete, so it's less than ideal, and I'm interested in trying that Perl fork you've suggested, for running the sleep, etc, in the background, but had a look at the doco, and you're right - it's confusing, and hasn't got many examples, either.  Do you know how I could just run this sub in the background?
mysub('add', '1,2,3', 'a@bc.com', 'Tel2');  # Call it

sub mysub
{
  my ($action, $lists, $emails, $name) = @_;
  sleep 2;
  ...etc...
}

Open in new window


Thanks.
0
 
LVL 27

Assisted Solution

by:wilcoxon
wilcoxon earned 2000 total points
ID: 35509764
The simplest way is...

if (fork == 0) {
    mysub('add', '1,2,3', 'a@bc.com', 'Tel2');
}

This is the "trick" with fork - fork returns the pid to the parent but 0 to the child so only the child will execute the code inside the if.

Before the end of your parent code, you probably want to do a wait.  Otherwise, you can end up with zombie processes.
0
 
LVL 12

Author Comment

by:tel2
ID: 35509898
Thanks wilcoxon,

So does the "fork" command run everything in the subsequent {block} in the background?

> Before the end of your parent code, you probably want to do a wait.  Otherwise, you can end up with zombie processes.

Wouldn't waiting defeat my purpose of forking?  I'm trying to make the parent code finish quickly, so it returns the webpage to the user, which is why I've moved the sleep to the subroutine, which will be run by the child process.  Are you with me?  Any suggestions?

Thanks.
0
 
LVL 27

Expert Comment

by:wilcoxon
ID: 35513154
You can try the %SIG trick mentioned in the fork docs and not do a wait (but it's noted to only work on some systems).

Making the wait the last command in the script after it's already done all of the output for the web page should also work.  This should give the user the web page and let them do other things while the script is waiting.  This definitely works for straight CGI - I assume it works for mod_perl but I'm not positive.
0
 
LVL 12

Author Comment

by:tel2
ID: 35517903
Hi wilcoxon,

Thanks for your comment about fork.

> "...this definitely works for straight CGI"
Just before raising this post, I tried having the sleep even at the very end of the script, and it strangely didn't make any difference to how long the web page took to appear.  So looking at the script I originally posted, I get the same delay behaviour whether I move the sleep to the beginning, the middle (where it is in that post), or the end.  I just tested it again now, on 3 different webhosts, and 2 different browsers (Firefox 3 & IE 6), and the same delay happens.  Are you saying it works differently for you?

Here's the code, to make sure we're on the same page:
#!/usr/bin/perl

use strict;
use warnings;
use CGI::Carp qw(fatalsToBrowser);

$| =1;

print <<EOF;
Content-Type: text/html; charset=utf-8\n
<html>
<body>
Before
EOF

print <<EOF;
After
</body>
</html>
EOF

sleep 5;

Open in new window

Thanks.
0
 
LVL 27

Expert Comment

by:wilcoxon
ID: 35562530
I guess I haven't tried in a long time.  It certainly used to work that way.  I don't have a personal web server right now to test on.  I wonder if that behavior has to do with Apache (and likely other web servers) doing things to speed up CGI scripts?
0
 
LVL 12

Author Closing Comment

by:tel2
ID: 35564008
Thanks for all your effort with this, wilcoxon.

Good to have you on the EE team!
0

Featured Post

[Webinar] Cloud and Mobile-First Strategy

Maybe you’ve fully adopted the cloud since the beginning. Or maybe you started with on-prem resources but are pursuing a “cloud and mobile first” strategy. Getting to that end state has its challenges. Discover how to build out a 100% cloud and mobile IT strategy in this webinar.

Question has a verified solution.

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

This article was originally published on Monitis Blog, you can check it here . Today it’s fairly well known that high-performing websites and applications bring in more visitors, higher SEO, and ultimately more sales. By the same token, downtime…
Australian government abolished Visa 457 earlier this April and this article describes how this decision might affect Australian IT scene and IT experts.
The viewer will learn how to count occurrences of each item in an array.
The is a quite short video tutorial. In this video, I'm going to show you how to create self-host WordPress blog with free hosting service.
Suggested Courses

873 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