ID:               39809
 User updated by:  e at osterman dot com
 Reported By:      e at osterman dot com
-Status:           Feedback
+Status:           Closed
 Bug Type:         CGI related
 Operating System: FC6
 PHP Version:      5.2.0
 Assigned To:      dmitry
 New Comment:

Thanks for your constructive input. I guess we'll have to rely on
creatively implemented timeouts w/in our application, as simply doing
connection timeouts won't work (php returns connected immediately, even
though the socket is not accepted).


Previous Comments:
------------------------------------------------------------------------

[2006-12-19 13:55:43] [EMAIL PROTECTED]

Agree. shutdown() should not be used together with FCGI_KEEP_CONN. 

PHP cannot return FCGI_OVERLOADED, because all PHP processes are busy
and nobody accepts new connection. The only way to detect this
situation - use connection timeout.

------------------------------------------------------------------------

[2006-12-18 22:09:32] e at osterman dot com

By changing the example code to use PHP's sockets (e.g.
socket_create/connect/read/write) allows one to use the socket_shutdown
as you suggested. But calling shutdown after the request defeats the
purpose of persistent connections, since that just negates the effect
of passing FCGI_KEEP_CONN. Connections cannot be reused to send
requests once they're shutdown after a request. 

So, it sounds like PHP's design decision is to support PHP_KEEP_CONN,
but when PHP_FCGI_CHILDREN is reached, all new connections are
queued/blocked. When a client releases its connection to a php-cgi
child process, then the next connection in the queue is handed over to
the next available child. While this makes a lot of sense when you're
dealing with only non-persistent connections or only a single php-cgi
server, it's not desireable when you have lots of persistent
connections or lots of fcgi servers. For example, in HTTP/1.1, servers
respond "503 Server too busy". If the client were notified in some way,
either by way of a closed connection, refused connection, or
FCGI_OVERLOADED packet, then the client could try another FCGI server.
But since that doesn't happen, the client must just sit and wait.
Perhaps, indefinitely or just timeout =( 

What is your take on this?


Best Regards,

Erik Osterman

------------------------------------------------------------------------

[2006-12-18 18:53:58] [EMAIL PROTECTED]

> <?
> $socket1 = FCGI_Connect('localhost', 1234);
> FCGI_Test($socket1);
> FCGI_Response($socket1);
> sleep(30);
> fclose($socket1);
> ?>

this code is not perferct, and this is the reason of bad behavior. You
should call shutdown() "man 2 shutdown" after writing request into
socket, but PHP doesn't implement such function.

<?
$socket1 = FCGI_Connect('localhost', 1234);
FCGI_Test($socket1);
shutdown($socket1, SHUT_WR); //we don't have this function
FCGI_Response($socket1);
sleep(30);
fclose($socket1);
?>

I cannot repeat your behavior with telnet. I always get "Connection
closed" after a timeout.

BTW you can insert debug output into fastcgi.c right after accept() and
try it.

------------------------------------------------------------------------

[2006-12-18 18:29:13] e at osterman dot com

For what it's worth, this shows some conflicting data. Perhaps I'm just
interpretting it wrong.

Start theh FCGI server in single process mode
# php-cgi -b 1234

Modify the test script as follows:
<?
$socket1 = FCGI_Connect('localhost', 1234);
FCGI_Test($socket1);
FCGI_Response($socket1);
sleep(30);
fclose($socket1);
?>

Now, the single process php-cgi server should not be accept()ing any
more connections for 30 seconds.

# telnet localhost 1234
Trying 127.0.0.1...
Connected to localhost.localdomain.
Escape character is '^]'.

Per my previous post, when a stream_socket_server server does not call
accept(), the 'telnet' session gets "connection refused". In this
example, it's not getting refused by the php-cgi server, which leads me
to believe that php-cgi might actually be calling accept. This could be
a implementation difference.. but I don't know.

Regards,

Erik Osterman

------------------------------------------------------------------------

[2006-12-18 18:20:11] e at osterman dot com

Dimitry,

You're example shocked me. I tried something similar making a simple
stream_socket_server, but didn't make the client in PHP.

<?
   $server = stream_socket_server('tcp://127.0.0.1:1234');
    if (!$server) {
        die('Unable to create AF_INET socket');
    }
    sleep(10);
?>

# telnet localhost 1234
Trying 127.0.0.1...
telnet: Unable to connect to remote host: Connection refused

I had expected the same behavior in PHP's fsockopen, but indeed, as you
said fsocketopen returns a valid resource even though the connection has
not yet been accept()'d by the server. More over, feof returns false and
fwrite to the socket returns the correct number of bytes "written".
stream_get_metadata returns nothing interesting either. 

How is a PHP fsockopen/stream_socket_client client to know when a
connection truely has been accept()'d?

The reason why this is all so important to us, is that we have a
cluster of frontend servers that use a pool of FCGI backend servers. We
need the busier frontend servers to dynamically open up more persistent
connections (FCGI_KEEP_CONN) to FCGI servers (and release them as
demand subsides). When a particular FCGI server is at capacity
(PHP_FCGI_CHILDREN), we need the client to try (in a round robin
fashion) another FCGI server. The current problem, as you understand by
now, is that the client get's stuck when connecting to an FCGI server at
capacity and timeout. 

As you've now suggested, it's apparently b/c they getting stuck waiting
for the accept(), but never get it.

What recourse does the client have?


Regards,

Erik Osterman

------------------------------------------------------------------------

The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at
    http://bugs.php.net/39809

-- 
Edit this bug report at http://bugs.php.net/?id=39809&edit=1

Reply via email to