Monday, 24 September 2018

PHP – Do not rely on set_time_limit too much

Php set_time_limit

Php has a function called set_time_limit which can be used to dynamically adjust the maximum execution time permitted to a script. It allows specifying the time in seconds and limits the script execution time to that many seconds.
The set_time_limit function whenever called, effectively extends the script execution time by that many seconds. So if the script has already run for 15 seconds and set_time_limit(30) is called, then it would run for a total of 30+15 = 45 seconds. That's how its designed to work.
The default time limit is generally 30 seconds and defined by the 'max_execution_time' option of php.ini
Use the ini_get function to get it.
1
ini_get('max_execution_time');
To find out the time already consumed by php use the getrusage function
1
2
3
4
5
$dat = getrusage();
echo $dat["ru_nswap"];         // number of swaps
echo $dat["ru_majflt"];        // number of page faults
echo $dat["ru_utime.tv_sec"];  // user time used (seconds)
echo $dat["ru_utime.tv_usec"]; // user time used (microseconds)
However the function itself can show varying behaviour across different platforms and environments and conditions. The documentation mentions
The set_time_limit() function and the configuration directive max_execution_time only affect the execution time of the script itself. Any time spent on activity that happens outside the execution of the script such as system calls using system(), stream operations, database queries, etc. is not included when determining the maximum time that the script has been running. This is not true on Windows where the measured time is real.
This means that any kind of activity that happens outside the script will not be controllable by set_time_limit. For example if you connect to a remote server using the socket_connect function or any other function that uses socket, then the time spend in the system call (function provided by underlying operating system) to connect will not be controllable by set_time_limit. Although the moment the control returns to the php script, the time limit would take effect.
So lets say if you are trying to ensure that scripts do not run out of bounds using set_time_limit, then make sure that you handle outside script calls separately and do no rely on set_time_limit for them. Otherwise the entire purpose would be defeated since the script still has a scope to consume more time.

Unlimiting with set_time_limit

A different scenario is, when you try to remove time restrictions on the php script to keep it running for as long as it wants or till an error occurs. To set unlimited time call the set_time_limit function with 0 as the parameter
1
set_time_limit(0);
But this will have different effects at different time. It would depend highly on how exactly the php script is being run.
If the script is being run from command line,
# /usr/bin/php /path/to/script.php
Then the time limit would be by default be 0 , means no time restriction. When running from apache, the max_execution_time is by default set to 30 seconds.
However when the script is run from a browser (that is inside an external environment like apache), and we need the php to keep outputting data to the browser, then php's set_time_limit function is not the only one controlling how long the php script can run and output the data to the browser. The server setup can also impose time restrictions on the php script.

Php handlers

If you are running php as using apache mod_php then you can use set_time_limit(0) to remove execution time limits on the php script. This will work as expected in most situations.
However when php is being run via mod_fcgid or mod_fastcgi or a fastcgi process manager like php-fpm then the running environment will have its own time restrictions on the script. You would notice that even after setting set_time_limit to 0, the script would end after a specific amount of time. This will be the time restriction placed by the execution environment.
For example mod_fastcgi has an option called "-idle-timeout" which controls the idle time of the script. So if the script does not output anything to the fastcgi handler for that many seconds then fastcgi would terminate it. The setup is somewhat like this
Apache <-> mod_fastcgi <-> php processes
Same thing happens with mod_fcgid. It too has an inbuilt time restriction. Php FPM has the option called request_terminate_timeout that will terminate the process after that many seconds.
So next time, don't be surprised when set_time_limit fails and check all php things properly.

0 comments:

Post a Comment