PHP shell_exe c через некоторое время возвращает пустую строку - PullRequest
2 голосов
/ 03 марта 2020

Я сделал консольную команду Symfony, которая использует pngquant для обработки и сжатия длинного списка изображений. Изображения считываются из файла CSV.

Пакет работает нормально до конца в локальной среде , но в рабочей среде он работает около 5 минут и затем он начинает возвращать пустой результат из команды shell_exec. Я даже сделал систему повторных попыток, но она всегда возвращает пустой результат:

// 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));
}

Проблема в том, что та же команда, выполняемая в другой оболочке в той же среде, работает нормально ! Я имею в виду, что когда я регистрирую ошибку, если я помещаю точно такую ​​же команду в другой экземпляр на том же сервере, она работает нормально.

Даже из журналов Symfony я не могу прочитать ни одной ошибки, где следует Я ищу более подробную ошибку?

Что может быть причиной этого? Память и процессор в порядке во время исполнения!

Ответы [ 2 ]

3 голосов
/ 03 марта 2020

После многих попыток я прочитал этот вопрос:

Компонент процесса Symfony2 - невозможно создать канал и запустить новый процесс

Решением было добавить вызов к gc_collect_cycles после гриппа sh во время l oop!

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% /
1 голос
/ 03 марта 2020

Если вы используете Symfony Framework (или нет), рекомендуется использовать Symfony Компонент процесса вместо shell_exec

В проекте Symfony вы можете найти установленный компонент процесса, однако, если это не так, вы можете загрузить компонент, используя:

 composer require symfony/process

Использование:

use Symfony\Component\Process\Exception\ProcessFailedException;
use Symfony\Component\Process\Process;

...


$process = new Process([
    $this->pngquantBinary,
    '--quality',
    sprintf('%d-%d', $minQuality, $maxQuality),
    '--output',
    $tempPath,
    '--force',
    $path
]);
$process->run();

// executes after the command finishes
if (!$process->isSuccessful()) {
    throw new ProcessFailedException($process);
}

$data = $process->getOutput();

см. symfony документация для получения дополнительной информации.

...