【问题标题】:PHP shell_exec returns empty string after a whilePHP shell_exec 一段时间后返回空字符串
【发布时间】:2020-03-03 08:33:33
【问题描述】:

我创建了一个 Symfony 控制台命令,它使用 pngquant 来处理和压缩一长串图像。图片是从 CSV 文件中读取的。

批处理在本地环境中工作正常,直到结束,但在舞台环境中工作大约 5 分钟,然后它开始从 @987654322 返回空结果@ 命令。我什至做了一个重试系统,但它总是返回空结果:

// escapeshellarg() makes this safe to use with any path
// errors are redirected to standard output
$command = sprintf(
    '%s --quality %d-%d --output %s --force %s 2>&1',
    $this->pngquantBinary,
    $minQuality,
    $maxQuality,
    escapeshellarg($tempPath),
    $path
);

// tries a few times
$data    = null;
$attempt = 0;

do {
    // command result
    $data = shell_exec($command);

    // error
    if (null !== $data) {
        $this->logger->warning('An error occurred while compressing the image with pngquant', [
            'command' => $command,
            'output'  => $data,
            'cpu'     => sys_getloadavg(),
            'attempt' => $attempt + 1,
            'sleep'   => self::SLEEP_BETWEEN_ATTEMPTS,
        ]);
        sleep(self::SLEEP_BETWEEN_ATTEMPTS);
    }

    ++$attempt;
} while ($attempt < self::MAX_NUMBER_OF_ATTEMPTS && null !== $data);

// verifies that the command has finished successfully
if (null !== $data) {
    throw new \Exception(sprintf('There was an error compressing the file with command "%s": %s.', $command, $data));
}

问题是在同一环境中的另一个shell中执行的同一命令可以正常工作!我的意思是,当我记录错误时,如果我将完全相同的命令放在同一服务器上的另一个实例中,则可以正常工作。

即使从 Symfony 日志中我也看不到任何错误,我应该在哪里查找更详细的错误?

这可能是什么原因造成的?内存和处理器在执行期间都很好!

【问题讨论】:

  • if (null !== $data) 不应该是if (null === $data) 吗?
  • 我将错误重定向到标准输出,因此如果运行正确,该命令将返回null(pngquant 命令没有输出)。
  • 这个问题让我感到困惑的是你说and then it starts returning empty result from the shell_exec command....但是“非空结果”是代码中的错误条件,所以“空结果”是预期的,对吧?
  • 作为空字符串的空结果是一个错误,但null 不是(在我的代码中)。空结果实际上应该包含错误消息,但系统没有返回它。
  • 不要使用shell_exec,而是使用exec,例如:exec(command,$output),打印$output并检查。

标签: php symfony shell-exec pngquant


【解决方案1】:

经过多次尝试,我读到了这个问题:

Symfony2 Process component - unable to create pipe and launch a new process

解决方案是在循环期间刷新后添加对gc_collect_cycles 的调用!

if ($flush || 0 === ($index % self::BATCH_SIZE)) {
    $this->em->flush();
    $this->em->clear();

    // clears the temp directory after flushing
    foreach ($this->tempImages as $tempImage) {
        unlink($tempImage);
    }
    $this->tempImages = [];

    // forces collection of any existing garbage cycles
    gc_collect_cycles();
}

重要提示:还要注意磁盘索引节点的数量

df -i
Filesystem      Inodes   IUsed  IFree IUse% Mounted on
udev            125193     392 124801    1% /dev
tmpfs           127004     964 126040    1% /run
/dev/vda2      5886720 5831604  55116  100% /

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-18
    • 2016-04-10
    • 1970-01-01
    • 1970-01-01
    • 2011-11-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多