“ require_once():需要打开失败”,但是文件存在并且可读

时间:2019-11-22 07:19:16

标签: php node.js redis locking pm2

自从几天以来,我的一个Cronjobs遇到了严重的问题。有时我会收到以下错误(每小时一次或两次):

  

PHP致命错误:require_once():无法在[...]中打开所需的'MailError.php'(include_path ='。:: / usr / www / users / web1 / master / sys / classes:..')

PHP无法打开的文件每次都会更改。此外,所需文件肯定存在并且可读。在Cronjob处于活动状态时,我试图用lsof | grep .php查找任何锁定的文件,但是没有锁定的* .php文件。

在我的require_once方法中调用spl_autoload_register

spl_autoload_register(function($className){
    $filePath = str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';

    $includePaths = explode(PATH_SEPARATOR, get_include_path());
    foreach($includePaths as $includePath){
        if(file_exists($includePath . DIRECTORY_SEPARATOR . $filePath)){
            require_once $filePath;
            return;
        }
    }
});

在第一次遇到问题之前,我在服务器上安装了一些新软件。 Node.js,用于进程监控的PM2,一个监听UDP套接字的Node.js脚本,以及Redis作为搜索结果缓存。我关闭了所有这些组件,现在看来Cronjob正在运行,再次没有任何错误。后来我一个接一个地打开这些组件,以检查哪个原因导致了错误,但看起来只有在打开每个组件时才会发生。

我不知道该问题的核心是什么,所以我希望我可以找到遇到相同或相似问题的人。

关于我的系统的一些有用信息:

  • 已安装Debian 9的受管服务器
  • Nodebr.js和Redis与Linuxbrew一起安装
  • PHP 7.3.11-cli
  • 没有使用防病毒软件

1 个答案:

答案 0 :(得分:0)

正如我在该线程Select() + UDP resulting in too many open files中发现的那样,该错误是由于超出了打开文件限制的结果。

在我的情况下,PHP脚本使用带有socket_create()socken_sendto()的UDP套接字,并使用socket_close()关闭它。关闭可能会失败,并且插座保持打开状态。在某个时候,打开文件的限制已被执行,PHP无法再包含任何其他文件。