5

This is not one of the regular questions if sleep is counted for timeout or stuff like that. Ok, here's the problem: I've set the max_execution_time for PHP as 15 seconds and ideally this should time out when it crosses the set limit, but it doesn't. Apache has been restarted after the change to the php.ini file and an ini_get('max_execution_time') is all fine. Sometimes the script runs for upto 200 seconds which is crazy. I have no database communication whatsoever. All the script does is looking for files on the unix filesystem and in some cases re-directing to another JSP page. There is no sleep() on the script.

I calculate the total execution time of the PHP script like this:

At the start of the script I set :

$_mtime = microtime();  
$_mtime = explode(" ",$_mtime);
$_mtime = $_mtime[1] + $_mtime[0]; 
$_gStartTime = $_mtime;

and the end time($_gEndTime) is calculated similarly.
The total time is calculated in a shutdown function that I've registered:

register_shutdown_function('shutdown');
.............
function shutdown()
{
   ..............
   ..............
   $_total_time = $_gEndTime - $_gStartTime;
   ..............
   switch (connection_status ())
    {
    case CONNECTION_NORMAL:
      ....
      break;
      ....
    case CONNECTION_TIMEOUT:
      ....
      break;
      ......
    }
} 

Note: I cannot use $_SERVER['REQUEST_TIME'] because my PHP version is incompatible. That sucks - I know.

1) Well, my first question obviously is is why is my PHP script executing even after the set timeout limit?
2) Apache has the Timeout directive which is 300 seconds but the PHP binary does not read the Apache config and this should not be a problem.
3) Is there a possibility that something is sending PHP into a sleep mode?
4) Am I calculating the execution time in a wrong way? Is there a better way to do this?


I'm stumped at this point. PHP Wizards - please help.

Edit: I just found out that the stream operations are not the cause with a few logs. The delay is just random within the script even when there are no streaming operations performed. Context switching may just be the reason. But I still dont have a clear answer. I looked up Real max_execution_time for PHP on linux but Im not sure I want to try that out. Any other suggestions?

Community
  • 1
  • 1
Joey Ezekiel
  • 1,017
  • 1
  • 11
  • 26
  • I believe file system operations are also not counted in time limit calculations. – lonesomeday Jun 29 '12 at 09:13
  • 1
    You know, you can use `microtime(true)` to get a `float` back right away... – deceze Jun 29 '12 at 09:16
  • @lonesomeday: Are you sure about that? – Joey Ezekiel Jun 29 '12 at 09:26
  • @JoeyEzekiel Yes. Look at the docs for `set_time_limit`. "Stream operations" are explicitly included – lonesomeday Jun 29 '12 at 09:26
  • @deceze Yes, I know. But this is legacy code and Im not really trying to look at the quality of code right now. Thanks anyway. – Joey Ezekiel Jun 29 '12 at 09:26
  • Sorry I have to ask, why do you need to reliably create a php timeout? – Toby Allen Jun 29 '12 at 11:53
  • @Toby Well, the script looks for a PDF file and if it finds it, the PDF stream is read and sent as a string to the caller - not a browser. The caller for example can be a Java application or otherwise. But before the PHP script can start looking for the file, there is a long delay which exceeds the max_execution_time but the PHP doesn't time out. With that said, I need a way for PHP to timeout no matter what - post the 15 second mark. Is that even possible? – Joey Ezekiel Jun 29 '12 at 12:08

2 Answers2

7

max_execution_time only limits script execution time itself - cpu time of your script. if the OS context switched to another process and spent some time there, it will not be counted as well. So measuring the real-world time and expecting a timeout after 30 seconds is not going to be true any given time. And of course, it disregards any system, exec or network times as well

poncha
  • 7,726
  • 2
  • 34
  • 38
  • 3
    Indeed.. Even waiting for DB queries or handling data streams are left out of the equation – Johan Jun 29 '12 at 09:22
  • I do not have any system, exec calls though nor do I call any external code. Are file system operations counted within the max_execution_time limit? Say, an fopen() – Joey Ezekiel Jun 29 '12 at 09:25
  • 1
    @JoeyEzekiel even if *you* do not do any operations that are not accounted for `max_execution_time`, OS context switching is still in play and you can do almost nothing about it. Well, you can `renice` the process running php (apache in this case), but i would not recommend it. – poncha Jun 29 '12 at 09:30
  • 1
    @JoeyEzekiel Yes, read the note on the PHP manual page: http://php.net/manual/en/function.set-time-limit.php Stream operations also affect the time-limit (and fopen/fread/etc are stream operations) – Johan Jun 29 '12 at 09:35
  • Ok, well - either its the context switching or the streaming operations that is causing this although I don't think the streaming operations should. Is there a way I can include the streaming operations within the max_execution_time? – Joey Ezekiel Jun 29 '12 at 10:55
  • 1
    @JoeyEzekiel You can't include those operations in `max_execution_time`. To overcome that (sort of) You can use [`register_tick_function`](http://php.net/register_tick_function) to register a callback that will check how much time has passed, but that's VERY inefficient (since the callback will be called a lot and will waste a lot of cpu cycles) and i'd strongly advise against it – poncha Jun 29 '12 at 12:24
  • Thanks for that Poncha. I need a way for PHP to timeout no matter what - post the 15 second mark. Is there a way to do it through Apache? – Joey Ezekiel Jun 29 '12 at 13:31
0

If you need to timeout after a certain length of time (as per comments) why not call

 $startscript = microtime();

 //do some stuff

if (microtime() - $startscript > 1500)
{
  dotimeout();
}


  // do more stuff

if (microtime() - $startscript > 1500)
{
  dotimeout();
}

  // do more stuff

if (microtime() - $startscript > 1500)
{
  dotimeout();
}

You get the jist. Not very pretty but might work.

Toby Allen
  • 10,997
  • 11
  • 73
  • 124
  • This could work when I know where the delay's are bound to happen. But in my case, the delays are random. So for eg: if the first check is passed and the microtime() - $startscript is any value that is < 1500 and if the delay happens just before the second check is called, it's the same story again. Thanks anyway...! – Joey Ezekiel Jun 30 '12 at 00:56