FastCGI PHP - unable to prematurely close connection to browser

Hi all!

I am optimizing a few of the PHP scripts by:

  • doing all that generates output to browser
  • closing connection to browser
  • doing some more processing

The processing bit cannot be avoided, but the speed of execution (from
visitors’ point of view) is awesome this way. The problem is that we
have tried migrating the script to NginX + FastCGI (it works on Apache +
mod_php) but it doesn’t close the connection anymore, it keeps it open
until the end… Which makes scripts slow again.

I am using Content-Length to allow server to figure out that all content
was already generated. This is the test case:

<? header("Connection: close"); // not sure we need this one header("Content-Encoding: none"); ignore_user_abort(true); ob_start(); echo ('Lets output something.'); // output Content-Length and flush buffers: $size = ob_get_length(); header("Content-Length: $size"); ob_end_flush(); flush(); // **************** // do some heavy processing here: sleep(5); function postproc() { flush(); sleep(5); } register_shutdown_function('postproc'); ?>

The browser shows this page immediately in Apache+mod_php but it waits
for 10 seconds in NginX + FastCGI.

I am a bit stuck here and would appreciate some help… Is this a
problem with FastCGI? Is there another way to do it?

Thanks!

Posted at Nginx Forum:

Hi,

I just tested your script and found that I needed to wait 10s to see the
response. I am using Windows XP, Apache 2.1.11 worker MPM, PHP 5.3.1

It did not work asynchronously as you expected. Am I missing something
here?

Regards

cactus wrote:

Hi all!

I am optimizing a few of the PHP scripts by:

  • doing all that generates output to browser
  • closing connection to browser
  • doing some more processing

The processing bit cannot be avoided, but the speed of execution (from
visitors’ point of view) is awesome this way. The problem is that we
have tried migrating the script to NginX + FastCGI (it works on Apache +
mod_php) but it doesn’t close the connection anymore, it keeps it open
until the end… Which makes scripts slow again.

I am using Content-Length to allow server to figure out that all content
was already generated. This is the test case:

<? header("Connection: close"); // not sure we need this one header("Content-Encoding: none"); ignore_user_abort(true); ob_start(); echo ('Lets output something.'); // output Content-Length and flush buffers: $size = ob_get_length(); header("Content-Length: $size"); ob_end_flush(); flush(); // **************** // do some heavy processing here: sleep(5); function postproc() { flush(); sleep(5); } register_shutdown_function('postproc'); ?>

The browser shows this page immediately in Apache+mod_php but it waits
for 10 seconds in NginX + FastCGI.

I am a bit stuck here and would appreciate some help… Is this a
problem with FastCGI? Is there another way to do it?

Thanks!

Posted at Nginx Forum:
FastCGI PHP - unable to prematurely close connection to browser

First of all - thank you for your answer, I really appreciate it.

This is interesting - I have re-checked and it takes me 32ms to get the
result on my development machine:
Server Apache/2.2.9 (Debian) PHP/5.2.6-1+lenny4 with Suhosin-Patch
X-Powered-By PHP/5.2.6-1+lenny4
(PHP is installed as mod_php)

Still, it is very important for me to be able to postpone processing. If
I can’t do it on NginX I will probably have to find another server that
can do this (overall load on the server is less important than quick
response times in this case). I’m really hoping it’s just a config
thing… :slight_smile:

From what I understand:

  • PHP offers no way to prematurely close the connection except by
    setting and reaching Content-Length
  • it is the web server (NginX / Apache) that can (should?) close the
    connection in this case

I can’t make PHP close the conenction, so my only hope is NginX. Can it
be told to do so? Am I missing something?

Thanks again!

Hoang Hoang Wrote:

The processing bit cannot be avoided, but the
figure out that all content

function postproc() {

51310


Posted via http://www.ruby-forum.com/.


nginx mailing list
[email protected]
nginx Info Page

Posted at Nginx Forum:

Hi,
Not really to change you method on doing things. but you still will
encounter slow response times for users eventually since that PHP
process is still processing things after that user is done and won’t
be ready for the next user until it is done processing that script. So
theoretical if you had 5 max PHP processes to handle client requests and
say each PHP script take 500ms to complete but only 100ms is until your
Connection: close. If 6 users hit your server at once. That user would
have to wait the full 500ms until a free PHP process is available to
process his request and then take the additional 100ms for it to see
content. So now his experience for the page to load up is it takes
almost 600ms.

Something i would suggest is using a messaging queue and a “few PHP
process’s that are just designed to process the queue” this allows you
to separate your user processing and your offline processing. Which will
also allow you to offload your work to another server if it starts
growing and such. here is website with some links to some message
queues.

v/r,
Rob

So, still searching for the culprit that doesn’t close the connection to browser when Content-Length is reached… :slight_smile: Any ideas?

Or is this a FastCGI issue? Is there any other way to use PHP with NginX?

I believe this is a FastCGI issue. And nginx buffer’s the FastCGI
response until FastCGI request is completed. The Header(“Connection:
close”); is only used to prevent using Keep-alive connection. It tells
the browser to terminate the connection and not keep them open, thus
having no effect on when the data gets to the client.

A suggestion that might work as your needing is stripping your apache
down to only using mod_php and anything else you might want. and
basically use it as a PHP process manager. Then you can just proxy your
requests to apache for the php requests and turn proxy_buffering off
Module ngx_http_proxy_module which then
should produce the results you require. This allow you to use nginx
for your static resources while just utilizing apache as just a PHP
manager.

v/r,
Rob

Rob, thank you for the idea! We have used it before on other problems,
though I had no idea there are libraries made to address this problem (I
used my own solution). Thanks for the link, the projects there look very
promising.

However, the way I see it, this approach is only useful if you want to
distribute the load across other machines or across time (so that major
work is done when the load is lower). In our case the application runs
on several machines already and we can add more if necessary. Also, the
work MUST be done at about the time the request was issued, so it cannot
wait 10 minutes when the load might be lower. I think in that case the
only solution is to compute when we get the requests, with the possible
optimization of returning the output before all work is done. Or am I
mistaken?

When the requests start getting slow (because they are waiting for other
requests to finish) we can just add more machines (or enlarge max.
number of PHP processes limit first :wink: and we’re done.

So, still searching for the culprit that doesn’t close the connection to
browser when Content-Length is reached… :slight_smile: Any ideas?

Or is this a FastCGI issue? Is there any other way to use PHP with
NginX?

Thanks again!

Posted at Nginx Forum:

I was hoping for a different answer - I guess I’ll just have to make a
few of configurations and test what works best.

Thank you for helping out! :slight_smile:

Posted at Nginx Forum:

cactus wrote:

is this a FastCGI issue?

You could try asking on a PHP mailing list, or looking through the PHP
source code, to see if there is a function call that will close the
FastCGI connection, while keeping the process open.

Tobia

Reinis R. Wrote:

http://php-fpm.org/wiki/Features#fastcgi_finish_re
quest.28.29

Thanks for the info, this is good news! :slight_smile:
I hope it gets in production soon - will try it out anyway, just out of
curiosity, I just need to find some extra time… :slight_smile:

Thanks to all, enjoy!

Posted at Nginx Forum:

From what I understand:

  • PHP offers no way to prematurely close the connection except by setting and reaching Content-Length

While I havent it used myself so not sure if it works 100% as expected
there is such feature if you use php with the FPM
patchset/manager - fastcgi_finish_request()

http://php-fpm.org/wiki/Features#fastcgi_finish_request.28.29

rr