I am making an API call to a service and need to timeout the call after 5 seconds and consider it a "fail" then proceed with the code. If it times out I want to save this to a $timeoutResult variable and then pass that all the way back to the javascript (I can do this part).
I'm just not sure how to do a timed function in PHP. I've seen the documentation on set_time_limit(5) but I'm not sure how to do it?
For example:
$response = $api_calls->apiCall($endpoint, $data); If this takes >5 seconds I want it to quit/consider the call a "fail" and then proceed onto my error handling further down the code.
I'm not sure how to stop the execution of THIS function by considering it a fail and proceeding.
Would something like this work?
set_time_limit(5);
$response = $api_calls->apiCall($endpoint, $data);
set_time_limit(0);
This way I set a timeout (which begins when this function inside a function is being called), it tries to execute, and if it finishes it then sets the time out back to infinity?
My cURL settings in apiCall() has a standard timeout of 10 seconds, but for this one particular call I need it to timeout after 5 seconds and then display an error if it times out.
You've not shown the code which actually makes the api call!
While its possible to to set a watchdog timer (SIGALRM) this is only an option on a POSIX system and only when running in the CLI sapi.
You mention that the code uses curl. This has lots of options for controlling timeouts - _CONNECTTIMEOUT[_MS], _LOW_SPED_LIMIT, _LOW_SPEED_TIME and _TIMEOUT[_MS] all documented in the manual.
I added an additional parameter to my apiCall() function which accepts an array.
I then looped through this array using
if(isset($extra_curl_options) && $extra_curl_options.length > 0){
foreach($extra_curl_options AS $k => $v) {
$http_request->setOption(constant($k), $v);
}
}
This will allow me to pass in multiple curl options to the apiCall for the future.
Related
Context :
I'm making a PHP websocket server (here) running as a DAEMON in which there is obviously a main loop listening for sockets connections and incoming data so i can't just create an other loop with a sleep(x_number_of_seconds); in it because it'll freeze my whole server.
I can't execute an external script with a CRON job or fork a new process too (i guess) because I have to be in the scope of my server class to send data to connected client sockets.
Does anyone knows a magic trick to achieve this in PHP ? :/
Some crazy ideas :
Keeping track of the last loop execution time with microtime(true), and compare it with the current time on each loop, if it's about my desired X seconds interval, execute the method... which would result in a very drunk and inconsistent interval loop.
Run a JavaScript setInterval() in a browser that will communicate with my server trough a websocket and tell it to execute my method... i said they where crazy ideas !
Additional infos about what i'm trying to achieve :
I'm making a little online game (RPG like) in which I would like to add some NPCs that updates their behaviours every X seconds.
Is there an other ways of achieving this ? Am I missing something ? Should I rewrite my server in Node.js ??
Thanks a lot for the help !
A perfect alternative doesn't seams to exists so I'll use my crazy solution #1 :
$this->last_tick_time = microtime(true);
$this->tick_interval = 1;
$this->tick_counter = 0;
while(true)
{
//loop code here...
$t= microtime(true) - $this->last_tick_time;
if($t>= $this->tick_interval)
{
$this->on_server_tick(++$this->tick_counter);
$this->last_tick_time = microtime(true) - ($t- $this->tick_interval);
}
}
Basically, if the time elapsed since the last server tick is greater or equal to my desired tick interval, execute on_server_tick() method. And most importantly : we subtract the time overflow to make the next tick happen faster if this one happened too late. This way we fill the gaps and at the end, if the socket_select timeout is set to 1 second, we will never have a gap greater than 1.99999999+ second.
I also keep track of the tick counter, this way I can use modulo (%) to execute code on multiple intervals like this :
protected function on_server_tick($counter)
{
if($counter%5 == 0)
{
// 5 seconds interval
}
if($counter%10 == 0)
{
// 10 seconds interval
}
}
which covers all my needs ! :D
Don't worry PHP, I won't replace you with Node.js, you still my friend.
It looks to me like the websocket-framework you are using is too primitive to allow your server to do other useful things while waiting for connections from clients. The only call to PHP's socket_select() function is hard-coded to a one second timeout, and it does nothing when the time runs out. It really ought to allow a callback or an outside loop.
Look at the http://php.net/manual/en/function.socket-select.php manual page. The last parameter is a timeout time. socket_select() waits for incoming data on a socket or until the timeout time is up, which sounds like what you want to do, but the library has no provision for it. Then look at how the library uses it in core/classes/SocketServer.php.
I'm assuming you call run() and then it just never returns to your calling code until it gets a message on the socket, which prevents you from doing anything.
I'm trying to make a proxy-like page that forwards an AJAX request to a SOAP server.
The browser sends 2 requests to the same page (i.e. server.php with different query string) every 10 seconds.
The server makes a soap call to the soap server depending on the query string.
All is working fine.
Then I put a sleep (40 secs) in the soap server to simulate a slow response and I also put a timeout on the caller to abort the call after some seconds.
server.php: Pseudo code:
$timeout = 10;
ini_set("default_socket_timeout", $timeout);
$id = $_GET['id'];
$wsdl= 'http://soapserver/wsdl'
$client = new SoapClient($wsdl,array('connection_timeout'=> $timeout));
print($client->getQuote($id));
If the browser sends an ajax request to http://myserver/server.php?id=IBM
the request stops after the timeout I set.
If I try to make a second call before the first stops, the second one doesn't not respect timeout.
i.e.
Request:
GET http://myserver/server.php?id=IBM
and after 1 second
GET http://myserver/server.php?id=AAP
Response:
after 10 seconds:
No data
after 20 seconds:
No data
I also tried to not use PHP SOAP and use curl instead but I got the same results.
I also tried to open 3 tabs on my browser and call:
http://myserver/server.php?id=IBM
http://myserver/server.php?id=AAP
http://myserver/server.php?id=MSX
The first one stops after 10 seconds, the second after 20 seconds and the third after 30 seconds.
Is this a normal behaviour or I miss something ?
Thanks in advance
You are probably starting sessions, and session_start() blocks a second call to it until the other request has 'freed' the session (in other words: has finished and will not write any data to the session anymore). For time consuming requests, don't start a session if you don't need one, and if you DO need one, get all the data that you need and then call session_write_close() BEFORE you doing the time-consuming thing. If you need to write to the session afterwards, just call session_start() again.
I wanted to execute a bunch of code for 5 seconds and if it has not finished executing within the specificed time frame I need to execute another piece of code..
Whether it's possible?
Ex..
There are two functions A and B
If A takes more than 30 seconds to execute the control should pass on to B
During function A you could periodically check how long the script has been executing, and if it goes over x seconds, run B:
function checkTime($start) {
$current = time();
$secondsToExecute = 5;
if (($start+$secondsToExecute) <= $current) {
func_b();
}
}
function func_a($start) {
// do some code
checkTime($start);
// do some code
checkTime($start);
// do some code
}
function func_b() {
// do something else
exit();
}
func_a(time());
http://php.net/manual/en/features.connection-handling.php
Set a time limit and a shutdown function, which checks if the status is 2 (timeout) and does your stuff if so.
One thing to note is that the time limit set this way only counts actual php processing time. Time spent with php waiting for another process or a database or http connection, etc, will not count and your time limit will not be considered reached.
If you need to count actual time that passed, even if it was not php processing time, you're going to have to go with the above suggested answer. Manually inserting that time check in places where it makes sense is the best, i.e. inside loops that you know may run too long, maybe even not on every iteration but on every N iterations, etc. Alternatively a more general approach is to use register_tick_function(), but that might lead to a noticeable performance hit with a low tick count, and you must take care to unregister it or use appropriate flags so you don't end up infinitely starting more and more calls to your timeout handling code once the timeout has happened.
Other approaches are also possible, you can register a handler for some signal using pcntl_signal() and have it sent to your process when the time limit is reached by an outside program ('man timeout' if you are on a linux box) or by a fork()-ed instance of your own php script, etc.
Is it possible to start a block of code (maybe just call a function) and if it doesn't execute within a certain time skip it.
//give this function 10 seconds to execute
$value = mega_function();// could take anything from 1-1000 seconds
//if 10 seconds have passed and the value is still not set, abort it and set $value = false;
No. You would have to either
Call the function inside an external file using curl or file_get_contents() - you can set a timeout there
Keep track of the time inside mega_function() and return() if necessary.
What does mega_function() do?
Try looking into threads, but it might be awkward to do something like this in PHP:)
Look at http://php.net/manual/en/function.pcntl-fork.php and all pnctl related functions for creating childs, sending signals between them, waiting for child to finish or killing threads.
I have php scripts that call perl scripts to do various things and sometimes I get it where it just goes on and on without getting a response back, this is based on the variable that is being passed to the perl script and I am doing a lot of different ones in succession so I can't get really debug it directly since I don't have a response from perl...
I would really like to just be able to set a php function or block of code to timeout after a certain number of seconds.. I have been searching on this but haven't found anything yet on how to do this,
I was thinking something like this could work but I don't think it would dynamically update the $time variable, but maybe there is a way to get this to work? Any advice is appreciated
$time = time();
$timeout = $time + 5; //just as an example
do {
// do stuff
} while ($time < $timeout)
Your best bet would be to use proc_open, sleep for your timeout amount and then call proc_terminate if the process still hasn't completed.
See http://us3.php.net/manual/en/book.exec.php for details on the proc_* family.
Well, I'm not so sure this question would have an answer based on how I asked it, so what I am going to do is do the perl call where php doesn't wait for a response and have perl write the output to a text file, then have php read this after specified number of seconds, I think this is the simplest way to do this, its just for a small app i am running on a local server