【发布时间】:2016-01-05 11:36:51
【问题描述】:
我们继承了一个平台,该平台有一个 crobjob,它每分钟使用不同的参数 (curl -s -o --url https://localhost/myscript.php?option=XYZ -k) 将本地 php 脚本卷曲 3 次。该脚本运行大约 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文档说它是每个会话,但 curl 没有使用 cookie,所以它应该是每个实例中的不同会话(而且如果它使用相同的会话,它总是会阻塞,因为我们总是执行三个脚本实例,它没有t); - 托管技术团队表示服务器中也没有错误 错误日志也不在这些问题的时间戳中的php错误日志中 发生。
我无法随意重现这些问题,但它们每天至少发生一次。 我想知道什么会干扰睡眠行为?如何检测或修复它?
附加信息:
- linux系统
- mysql 5.5
- 阿帕奇
- php 5.3
- php
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?),它是从哪里来的,有什么办法可以避免它?
Edit3:我添加了代码来处理带有 pcntl_signal 的信号(尝试从信号 1 注册到 255)并记录它们,问题仍然存在,但日志仍然是空的。
【问题讨论】:
-
只是一个提示,并不是真正的解决方案:我会使用唯一标识符 (
uniqid()) 而不是$option来查看它是否确实只有一个文件.此外,尝试记录sleep()的返回值 - 一旦它捕获到信号,它是肯定的,如果发生错误,它是 false。 -
感谢您的建议,一定会记录
sleep的返回值
标签: php apache curl cron sleep