php sleep 功能奇怪的行为

标签 php apache curl cron sleep

我们继承了一个平台,该平台有一个 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/

相关文章:

php - Google map 文档使用已弃用的 PHP - 我该如何更新它?

php - 使用 for 循环从 MySQL 查询中增量选择值

PHP:$_FILES 中 'type' 索引的来源是什么?

java - 将JPanel中生成的数据导出到excel

php - POST 在 PHP 中使用 cURL 和 x-www-form-urlencoded 返回访问被拒绝

php - PHP 5.6.4 中不再定义 CURLCLOSEPOLICY_LEAST_RECENTLY_USED : is it better to replace with something else or to comment out the reference?

php - 如何在 Ubuntu 14.04 上安装 php7 (zts) + pthreads

php - 实现推送通知系统的最佳方式

apache - 如何在 Apache mod_jk JkMount 中表示问号 '?'?

php - 在 curl/php 中保持事件状态