查找PHP脚本终止源的最佳实践

时间:2010-11-24 23:37:41

标签: php apache debugging

我有一个PHP脚本,它从数据库中抓取一大块数据,对其进行处理,然后查看是否有更多数据。这个过程无限期地运行,我在一台服务器上一次运行其中几个。

它看起来像:

<?php
    while($shouldStillRun)
    {
       // do stuff
    }
    logThatWeExitedLoop();
?>

问题是,经过一段时间后,某些事情导致进程停止运行,我无法对其进行调试并确定原因。

到目前为止,这是我用来获取信息的内容:

  • error_log - 记录所有错误,但错误日志中未显示任何错误。
  • register_shutdown_function - 注册了自定义关机功能。这确实被调用,所以我知道进程没有被服务器杀死,它被允许完成。 (或者至少我认为这是被调用的情况?)
  • debug_backtrace - 在我的自定义关闭功能中记录了debug_backtrace()。这只显示一个调用,这是我的自定义关闭功能。
  • 记录到达脚本结尾 - 在循环之外,我有一个记录脚本退出循环的函数(因此会正常到达源文件的末尾)。当脚本随机死亡时,它不会记录这个,所以无论什么杀死它,都会在处理过程中杀死它。

您会建议使用哪些其他调试方法来查找罪魁祸首?

注意:我应该补充一点,这不是max_execution_time 的问题,对于这些脚本是禁用的。被杀之前的时间是不一致的。它可以在它死亡之前运行10秒或12小时。


更新/解决方案:谢谢大家的建议。通过记录输出,我发现当MySql查询失败时,脚本被设置为die()。 D'哦。更新它以记录mysql错误然后终止。现在就像魅力一样工作!

6 个答案:

答案 0 :(得分:2)

请记住,PHP在ini文件中有一个变量,表示脚本应该运行多长时间。 max-execution-time

确保您没有检查过,或使用set_time_limit()来增加执行时间。该程序是通过Web服务器还是通过cli运行的?

添加:我使用PHP的糟糕体验。查看我今年早些时候写的一些背景脚本。抱歉,PHP是一种糟糕的脚本语言,可以在很长一段时间内完成任何操作。我看到较新的PHP(我们尚未升级到)添加了强制GC运行的功能。我一直遇到的问题是使用太多的内存,因为GC几乎从不运行来清理自己。如果你使用递归引用自己的东西,它们也永远不会被释放。

创建一个包含100,000个项目的数组会产生内存,但是然后将数组设置为空数组或将其全部拼接出来,不会立即将其释放,并且不会将其标记为未使用(也就是说新的100,000个元素数组会增加存储器)。

我个人的解决方案是写一个永远运行的perl脚本和system(“php my_php.php”);在需要时,解释器将完全释放。我目前支持5.1.6,这可能会在5.3+或至少修复,现在他们有GC命令可以用来强制GC清理。

简单脚本

#!/usr/bin/perl -w

use strict;

while(1) {
  if( system("php /to/php/script.php") != 0 ) {
    sleep(30);
  }
}

然后在你的PHP脚本

<?php

// do a single processing block

if( $moreblockstodo ) {
  exit(0);
} else {
  // no? then lets sleep for a bit until we get more
  exit(1);
}

?>

答案 1 :(得分:2)

我会记录脚本的内存使用情况。也许它获得了太多的内存,达到了内存限制并且死了?

答案 2 :(得分:0)

我将函数的状态记录到每个循环中几个不同位置的文件中。

您可以使用var_export($varname,true)表单将大多数变量的内容作为包含var_export的字符串。

您可以将其记录到某个文件中,并密切关注它。日志结束前函数的最新状态应提供一些线索。

答案 3 :(得分:0)

听起来无论发生什么都不是标准的php错误。您应该能够使用try ... catch语句抛出自己的错误,然后记录该语句。除此之外我没有更多细节因为我在手机上远离电脑。

答案 4 :(得分:0)

我之前在我们的一个工作项目中遇到过这个问题。我们有类似的设置 - 如果有任务要完成,PHP脚本会检查数据库(例如发送电子邮件,更新记录,处理一些数据)。 PHP脚本里面有一个while循环,设置为

while(true) {
    //do something
}

过了一会儿,剧本也会以某种方式被杀死。我已经尝试了大部分已经说过的内容,例如设置max_execution_time,使用var_export记录所有输出,放置try_catch,制作脚本输出(php ...&gt; output.txt)等我们从来没有能够找出问题所在。

我认为PHP本身不是为了完成后台任务而构建的。我知道它没有回答你的问题(如何调试),但我们的工作方式是我们使用cronjob每5分钟调用一次PHP文件。这类似于Jeremy使用perl脚本的答案 - 它确保解释器在执行完成后是免费的。

答案 5 :(得分:0)

如果这是在Linux上,请尝试查看系统日志 - 该过程可能被OOM(内存不足)杀手杀死(不太可能,如果发生这种情况,您也会看到其他问题),或者分段错误(某些版本的PHP不喜欢某些版本的扩展,导致奇怪的崩溃)。

相关问题