我们继承了一个平台,该平台有一个 crobjob,每分钟使用不同的参数将本地 php 脚本 curl 三次 (curl -s -o --url https://localhost/myscript.php?option= XYZ -k
).该脚本运行大约 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 启动时重叠)但有时我们有两个问题可以通过日志确认:
- 有时它会休眠不到 13 秒(a 时间长短不一,始终少于 13 分钟);
- 有时脚本会停止(在“Will sleep”之后不再记录,我们可以验证没有正在执行数据库操作)。 [在编辑 2 中对此进行更新]
我们已经调查了可能的原因,但找不到任何原因:
- php
max_execution_time
设置为 240 秒并且脚本从不 需要超过一分半钟; sleep
文档说它是针对每个 session 的,但是 curl 没有使用 cookie,所以它在每个实例中应该是不同的 session (而且如果它使用相同的 session ,它总是会阻塞,因为我们总是执行三个脚本实例,它没有);- 托管技术团队表示服务器中都没有错误 错误日志也不在 php 错误日志中的时间戳中,这些问题所在 发生。
我无法随意重现这些问题,但它们至少每天发生一次。 我想知道什么会干扰 sleep 行为?如何检测或修复它?
附加信息:
- linux系统
- MySQL 5.5
- Apache
- php 5.3
- php
max_execution_time
设置为 240
编辑 1: 澄清一下:实际上我们有 3 个选项,因此它写入 3 个日志文件,每个选项一个。在任何给定时间,每个选项最多可以运行两个实例(同一选项的每个实例重叠少量时间)。
Edit2:根据@Jan 的建议,我在 sleep 函数结果中添加了日志。该脚本已经停止了该日志:
[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
文档:
If the call was interrupted by a signal, sleep() returns a non-zero value. On Windows, this value will always be 192 (the value of the WAIT_IO_COMPLETION constant within the Windows API). On other platforms, the return value will be the number of seconds left to sleep.
因此根据文档和日志,sleep
似乎由于中断而被缩短。
我怎么知道是什么中断导致了这个(pcntl_signal
?),它是从哪里来的,有什么办法可以避免吗?
Edit3:我添加了代码来处理带有 pcntl_signal 的信号(尝试从信号 1 到 255 注册)并记录它们,问题仍然存在,但日志仍然是空的。
最佳答案
您可以使用 pcntl_signal 定义信号处理程序。
使用这些处理程序,您可以在发生中断时进行记录。但是据我所知,您无法检测到它的来源。
您还可以使用 pcntl_alarm 来处理延迟的作业。 Check PHP Manual - PCNTL Alarm
关于php sleep 功能奇怪的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34610807/