Change to timeout use

php.internals

Andreas Schiffler

20 years ago
Hi all, I am new to php source code hacking, but got into it for a particular reason: I need sub-second SOAP request timeouts. To qualify the reasoning behind this sub-second timeout requirement a bit further, let me explain what it is used for: We are implementing a system that changes webcontent based on a remote SOAP service (i.e. customer database) and we want to never wait more than - say - 250ms for this to complete. Currently the best I can do is 1 sec connection timeout (in SoapClient() using the connection_timeout parameter) and 1 sec socket-read timeout (using ini_set() on the default_socket_timeout parameter). Assuming the remote SOAP server is down or slow, every pagerender with the SOAP request in it would get delayed by at least 1 sec, which is unacceptable in our case. BTW, comparing the PHP situation with other SOAP implementations, we have typically millisecond timeouts available: - Java (apachesoap): milliseconds - Java (axis): milliseconds - .NET: milliseconds - perl (SOAP::Lite): seconds Currently all socket/connection timeouts in PHP are implemented with second resolution. This is an unnecessary limitation in my view and I would love for this to be changed in mainstream PHP. I believe the effort to do so is minimal and has no impact to the users. The timeout numbers are usually used to populate a "tv" struct - in the current PHP code only the tv.tv_sec is typically set. So the change would simply be to promote default_socket_timeout (and similar variables) to a float and use the fractional part to properly populate tv.tv_usec with a microsecond number. In fact I found locations where the default_socket_timeout parameter is assumed to be a float (ext/standard/fsock.c - line 66). Also this simple code shows the local default_socket_context to accept a float parameter: <?php ini_set("default_socket_timeout",0.5); phpinfo(); ?> while ext/standard/file.h - line 113 stores it as a long. So a quick review of how this parameter is used throughout the code might be a-good-thing (TM) anyhow. An example implementation of the new, float resulution timeout use for the SoapClient/SoapServer is a few lines in ext/soap/soap.c and ext/soap/php_http.c as follows: soap.c if (zend_hash_find(ht, "connection_timeout", sizeof("connection Z_TYPE_PP(tmp) == IS_DOUBLE && Z_DVAL_PP(tmp) > 0.0) { add_property_double(this_ptr, "_connection_timeout", Z_ } php_http.c if (zend_hash_find(Z_OBJPROP_P(this_ptr), "_connection_timeout", sizeof Z_TYPE_PP(tmp) == IS_DOUBLE && Z_DVAL_PP(tmp) > 0.0) { tv.tv_sec = floor(Z_DVAL_PP(tmp)); tv.tv_usec = (1000000.0*(Z_DVAL_PP(tmp)-floor(Z_DVAL_PP(tmp)))); timeout = &tv; } Similarly changes in the main PHP code could look something like this (assuming the var is a float): main/streams/transport.c default_timeout.tv_sec = floor(FG(default_socket_timeout)); default_timeout.tv_usec = (1000000.0 * (FG(default_socket_timeout)-floor(FG(default_socket_timeout))) ); The files that need to be changed are limited. grep -c default_socket_timeout ind . -name "*.[ch]" | grep -v :0 gives ./ext/imap/php_imap.c:4 ./ext/standard/file.c:1 ./ext/standard/file.h:1 ./ext/standard/fsock.c:1 ./ext/standard/streamsfuncs.c:2 ./ext/openssl/xp_ssl.c:2 ./main/streams/transports.c:2 ./main/streams/xp_socket.c:3 ./main/network.c:2 grep -c default_socket_timeout ind . -name "*.[ch]" | grep -v :0 gives ./ext/ftp/ftp.c:2 ./ext/curl/streams.c:1 ./ext/soap/php_http.c:1 ./ext/session/session.c:3 ./ext/sockets/sockets.c:5 ./ext/standard/uniqid.c:1 ./ext/standard/lcg.c:1 ./ext/standard/fsock.c:1 ./ext/standard/streamsfuncs.c:4 ./ext/openssl/xp_ssl.c:2 ./main/streams/xp_socket.c:2 ./main/network.c:2 Best regards Andreas

Wez Furlong

20 years ago
There's not much difference between .25 and 1 second. If you're talking soap on each page render, you're probably doing something wrong anyway; you should have some kind of cache in your web app. That's not to say that we won't fix this issue, but we're not in a rush to do so. If you're feeling motivated, we'll gladly accept a patch against HEAD that implements this; otherwise, you'll have to wait until someone is motivated enough. --Wez. On 12/21/05, Andreas Schiffler <aschiffler@ic-agency.com> wrote:

Andreas Schiffler

20 years ago
Wez,
>There's not much difference between .25 and 1 second. > >
Ah, this may be so for the traditional use of webservices. But for eCommerce applications for example speed is king and its also very important to provide consistent speeds (i.e. not hang). I don't have published reference links on this, but some of our private documents point to a target of max. 200ms for an ad-serving related webservice (which is technically absolutely feasable anyhow, even across the country).
>If you're talking soap on each page render, you're probably doing >something wrong anyway; you should have some kind of cache in your web >app. > > >
No - by nature of our webapp, every request is unique and a cache would not help. The PHP soap implementation is very fast by the way ... my benchmarks indicated 3-4ms request times on the LAN (without doing anything useful inside the request). This compares to over 30ms for the mod_perl/Soap::Lite implementation (and I haven't tested Java or .Net)
>That's not to say that we won't fix this issue, but we're not in a >rush to do so. >If you're feeling motivated, we'll gladly accept a patch against HEAD >that implements this; otherwise, you'll have to wait until someone is >motivated enough. > > >
OK. I understand that. I'll try my best to come up with a patch set then. Can someone point me to some documentation on how to do this? Is someone willing to assist me in making this patch? Bye Andreas

Wez Furlong

20 years ago
On 12/21/05, Andreas Schiffler <aschiffler@ferzkopp.net> wrote:
> >There's not much difference between .25 and 1 second. > Ah, this may be so for the traditional use of webservices. But for > eCommerce applications for example speed is king and its also very > important to provide consistent speeds (i.e. not hang). I don't have > published reference links on this, but some of our private documents > point to a target of max. 200ms for an ad-serving related webservice > (which is technically absolutely feasable anyhow, even across the country).
OK, but this is in the case where you've got an error, right? What do you do if you don't get a response, and how often does it happen?
> OK. I understand that. I'll try my best to come up with a patch set then. > Can someone point me to some documentation on how to do this? Is > someone willing to assist me in making this patch?
It sounded like you'd identified all the places that needed adjusting; just go ahead and try making it work :) You can ask questions here on internals@ and I'm sure you'll get some help if you ask the right questions (try to be as specific as possible so it's easier to answer). Hope that helps :) --Wez.

sebastian

20 years ago
> The PHP soap implementation is very fast by the way ... my benchmarks > indicated 3-4ms request times on the LAN (without doing anything useful > inside the request). This compares to over 30ms for the > mod_perl/Soap::Lite implementation (and I haven't tested Java or .Net)
Can you provide code and related info about these benchmarks?

Andreas Schiffler

20 years ago
Sebastian wrote:
>>The PHP soap implementation is very fast by the way ... my benchmarks >>indicated 3-4ms request times on the LAN (without doing anything useful >>inside the request). This compares to over 30ms for the >>mod_perl/Soap::Lite implementation (and I haven't tested Java or .Net) >> >> > >Can you provide code and related info about these benchmarks? > > >
http://www.ferzkopp.net/Software/SoapBench.zip

steve roussey

20 years ago
> There's not much difference between .25 and 1 second.
Actually, there is. It depends on the length of time of a typical page request (and the proportion of the delay to the typical time), and the hardware setup to handle that. The 4x slowdown can cause a cascade effect as it might cause more than 4x simultaneous connections on the target (causing it to slow down, and the problem to keep growing). That gets amplified by the number of webservers a bit. I don't use SOAP in such a way, but it is analogous to MySQL queries, and having a 1s time for a common query can lead to all sorts of problems. The reason I'm chiming in here is to suggest that if this is looked at, that it be made universal for all network timeouts. I'm thinking MySQL in particular, as there could be a class of websites that don't use custom connection pooling handlers on their webservers to get around this (useful, for example, if switching to backup servers). So maybe fractional seconds for network related timeouts could be a wishlist item for PHP 6? Personally, I wouldn't mind connection pooling too. I like to dream... :)

Wez Furlong

20 years ago
The problem isn't the duration of the soap query call, it's how long to wait before giving up on establishing the connection. The connect timeout is completely independent from the soap call duration or the work that it performs. --Wez. On 12/21/05, steve <iamstever@gmail.com> wrote:

Rasmus Lerdorf

20 years ago
steve wrote:
> Personally, I wouldn't mind connection pooling too. I like to dream...
And where would such a pool live?