我们继承了一个平台,它有一个crobjob,每分钟使用不同的参数(curl -s -o --url https://localhost/myscript.php?option=XYZ -k
)卷曲一个本地php脚本三次。该脚本运行大约1分钟,并且具有相同选项的可能的多个实例重叠一段时间。该脚本在每个选项中记录一个不同的文件,每个日志以脚本启动时的时间戳开始,因此它充当实例标识符。
脚本有这个骨架:
<?php
$option=XYZ;
$scriptId = time();
$file = "log_$option.txt";
file_put_contents($file,"\n$scriptId: Start\n",FILE_APPEND);
session_start();
$expires = time()+60;
file_put_contents($file,"\n$scriptId: Expires at $expires\n",FILE_APPEND);
while(time()<$expires){
file_put_contents($file,"\n$scriptId: Not expired at ".time()."\n",FILE_APPEND);
switch($option){
case X:
do_db_stuff();
break;
...
}
file_put_contents($file,"\n$scriptId: Will sleep at ".time()."\n",FILE_APPEND);
sleep(13);
file_put_contents($file,"\n$scriptId: Woke up at ".time()."\n",FILE_APPEND);
}
file_put_contents($file,"\n$scriptId: Finished at ".time()."\n",FILE_APPEND);
通常这个脚本运行正常(即使它们在实例A最后一次休眠并且实例B开始时重叠)但有时我们可以通过日志确认两个问题:
我们已经调查了可能的原因但找不到任何原因:
max_execution_time
设置为240秒,脚本永远不会
需要超过一分半的时间; sleep
文档说它是每个会话但curl没有使用cookie所以它应该是每个实例中的不同会话(并且如果它使用相同的它总是会阻塞,因为我们总是执行三个脚本实例,它没有); 我不能随意重现这些问题,但它们每天至少发生一次。 我想知道的是什么可以干扰睡眠行为?我该如何检测或修复它?
其他信息:
max_execution_time
设置为240 编辑1:只是为了澄清:实际上我们有3个选项,因此它会写入3个日志文件,每个选项对应一个。在任何给定时间,每个选项最多可以运行两个实例(相同选项的每个实例都会占用少量时间)。
Edit2:根据@Jan建议,我将日志添加到睡眠功能结果中。脚本已经停止了一次该日志:
[2016-01-05, 13:11:01] Will sleep at 2016-01-05, 13:11:29
[2016-01-05, 13:11:01] Woke up at 2016-01-05, 13:11:37 with sleep return 5
[2016-01-05, 13:11:01] Not expired at 2016-01-05, 13:11:37
[2016-01-05, 13:11:01] Will sleep at 2016-01-05, 13:11:37
[2016-01-05, 13:11:01] Woke up at 2016-01-05, 13:11:38 with sleep return 13
... no more log from instance [2016-01-05, 13:11:01] ...
[2016-01-05, 13:12:01] Start
根据sleep
文档:
如果呼叫被信号中断,sleep()将返回非零值。在Windows上,此值始终为192(Windows API中WAIT_IO_COMPLETION常量的值)。在其他平台上,返回值将是剩余的休眠秒数。
因此,根据文档和日志,似乎sleep
由于中断而缩短了。
我如何知道导致此问题的中断(pcntl_signal
?),它来自何处以及是否有任何方法可以避免它?
编辑3:我添加了代码来处理pcntl_signal信号(尝试从信号1到255注册)并记录它们,问题仍然存在,但日志仍为空。
答案 0 :(得分:1)
您可以使用 pcntl_signal 定义信号处理程序。
使用这些处理程序,您可以在发生中断时进行记录。但AFAIK你无法察觉它来自哪里。
此外,您可以使用 pcntl_alarm 来处理延迟的工作。 Check PHP Manual - PCNTL Alarm
答案 1 :(得分:0)
鉴于你的堆栈,中断信号可能来自apache。根据Apache在堆栈上与PHP通信的方式,Apache配置中有几个超时选项可以通过脚本执行进行推断。
如果你的cron在localhost上调用curl,也许它可以直接调用PHP文件,所以避免使用apache进程来保持请求活着?您必须使用php.ini
值编辑专用CLI max_execution_time
文件。