我在PHP 5.6.26上使用FPM开发一个流浪盒子。
我正在做一个测试电池,用一系列请求击中REST端点,试图捕获远程端的间歇性错误。在我的电池中,我有一个变量来表示要运行的重复次数。因为我不知道每个请求需要多长时间,所以有时大量的重复会导致脚本超时,并且我将无法看到已经运行的请求的结果。
因此,我决定最大化测试运行次数,而不是指定重复次数。我监视脚本执行了多长时间,如果我们使用ini_get('max_execution_time')
接近超时,就尝试保释。
然而,我注意到使用这种方法,我没有得到和以前一样多的测试运行。我做了更多的调试,发现可以超过max_execution_time!
我做了更多的调查,发现PHP-FPM有自己的超时限制,当我的脚本死亡时,我达到了这个限制:
[Fri Oct 28 19:41:04.491557 2016] [proxy_fcgi:error] [pid 2343:tid 140619049568000] (70007)The timeout specified has expired: [client 192.168.253.1:52431] AH01075: Error dispatching request to :, referer: http://local.mysite.com/test
所以,知道我想运行测试只要我允许,我如何得到实际的超时值从PHP-FPM在我的脚本?
我知道/etc/php-fpm.d/www.conf
中有设置,但我不想在脚本中硬编码该值,以防它发生变化。
总之,用getrusage()
,不要用time()
。
现在再多一点。受max_execution_time
限制的脚本执行时间是在脚本内花费的时间。来自set_time_limit doc
,第二条注释:
方法执行之外的活动所花费的时间脚本,例如使用system()的系统调用,流操作,在确定最大值时不包括数据库查询等脚本运行的时间。在Windows上不是这样其中测量时间为实数
最简单的例子:sleep(35)
与max_execution_time
= 30是可以的,正如你已经注意到的。
如果您使用time()
,您将总是在30秒后结束,即使您还有时间编写脚本。
所以你需要脚本中的实时时间,而不是真实世界的时间。为了得到这种时间,你有getrusage()
函数和它的答案ru_utime.tv_sec
和ru_utime.tv_usec
键。
第二步,当您使用PHP-FPM时,它是响应多个请求的相同进程。这意味着一个进程将这些ru_utime
的统计信息从一个请求传递到另一个请求。您必须在脚本开始时获得ru_utime.tv_sec
值并计算差异。当这个差值接近max_execution_time
时,可以结束重复/循环。
例如:
$gru = getrusage();
$gru_start = $gru['ru_utime.tv_sec'];
$gru_end = $gru_start;
// Considering that duration of one iteration in
// the next while loop is less than 1 second,
// we use this as the max limit.
$max_time = ini_get('max_execution_time') - 1;
while ($gru_end - $gru_start < $max_time) {
// long and repetitives tasks
// ....
// could use a counter to not call this function at each iteration,
// but only once every 10, 100, 1000 ... times.
$gru = getrusage();
$gru_end = $gru['ru_utime.tv_sec'];
}
或者将其转化为函数…
希望它能带你走得更远。老实说,我在这里的理解有点有限,这个解决方案可能有点脆弱,请适当小心使用。