3

我正在使用主管(http://supervisord.org/)来守护一个相当标准的 PHP 脚本。该脚本的结构类似于:

while (1) {
//  Do a SQL select
//  for any matching rows, do something
//  if I have been running for longer than 60 mins, exit
}

今天,这个脚本(已经相当稳定一段时间了)挂了。它没有崩溃(即发出 SIGHUP 或 SIGTERM 信号),这会提醒 supervisord 重新启动进程。它在处理过程中没有遇到任何错误,这些错误要么被脚本捕获,要么至少触发了致命错误并退出。而不是这些“可捕获”的场景,它只是坐在那里。我们确实有一个 cron 作业设置,每小时运行一次,以通过 supervisorctl 钩子重新启动脚本,因为似乎普遍认为 PHP 脚本在内存方面存在泄漏,如果运行时间很长,最好重新启动。该脚本在重新启动后正常恢复操作。

我的问题:如何检测到该脚本已挂起?如果我没有以某种方式提醒我该状态,我什至无法开始诊断或解决它为什么挂起的问题。我正在寻找解决此问题的软件解决方案,或者我可以采用某种方法自行编写解决方案(在 PHP、Python、perl 或 shell 中)。

该脚本是用 PHP 5.2.6 编写的,并在最新的 RHEL 5 服务器上运行。

请让我知道我是否可以分享任何其他信息,如果它有助于提供更棒的解决方案。

谢谢!

沙希布·R。

4

3 回答 3

2

由于这是脚本挂起的情况,PHP 可能不会处理任何可以检测到此挂起的附加代码。出于这个原因,我建议修改脚本以保留日志。这将允许主脚本让它之外的任何东西都知道它仍在运行,并且通过一些放置得当的更新,它还可以帮助查明哪里出了问题。

日志记录可以写入文件或数据库,并且应该至少包含脚本状态的指示符,例如最后修改日期。如果这个脚本不是一直在运行,那么也应该有一些东西表明它正在运行或已经停止。在您给出的示例中,日志写入将在 while 循环中至少发生一次,可能更多。打开指针或数据库连接需要时间/资源,因此我建议只记录需要的内容。(注意:如果使用文本文件方法,则需要在每次写入后立即关闭文件。)

例子:

while (1) {
    log('Running SQL select');
    //  Do a SQL select
    log('Results retrieved');
    //  for any matching rows, do something
    //  (check log) if I have been running for longer than 60 mins, exit
}

function log($msg) {
    // Write timestamp, $msg to log
}

一个单独的脚本需要检查日志并报告任何错误,如果它受到导致主脚本挂起的原因的影响,这可能会出现问题,但我想不出替代方案。

关于内存,如果你还没有使用mysql_free_result,你应该试一试。

于 2011-08-26T04:46:19.073 回答
1

我的建议与@Shroder 所描述的类似,但更进一步。每次运行时,您都将创建一个日志/数据库条目,它将带有时间戳+事务感知(您将在运行开始时将事务更新为processing,然后在完成后,使用completed.

另一方面,您将运行一个简单的 cron 检查,并通过使用时间戳和事务状态查看当前时间是否大于您的触发器(60 分钟等)。那时您会发出警报等;

于 2011-08-26T05:02:57.077 回答
0

这很简单!只需计算从循环开始到当前执行点的时间差。

$starttime = microtime(true);
while (1) 
{
    //Do your stuff here
    //More SQL, whatever you need


    //Put this at the end of the loop
    $curtime = microtime(true);
    $timetaken = $curtime - $starttime;
    if($timetaken > (60 * 60))
    {
        break;
    }
}

microtime(true)将返回自 Unix 纪元以来的秒数,因此如果我们从当前时间减去我们开始的时间,我们会得到所用/经过的时间,如果超过60*60秒数则退出循环。

于 2011-08-25T23:07:19.027 回答