Как в Yii2 реализовать конвертацию видео с помощью FFmpeg?

В Yii2-приложении в очереди выполняется Job, который на сервере запускает FFmpeg для перекодирования видео из MP4 в HLS. Для коротких файлов (до ~11 минут и до ~2 ГБ) всё проходит корректно, но при попытке обработать, например, 20‑минутное видео кодирование обрывается — похоже, FFmpeg неожиданно завершает работу. Лимиты времени и памяти уже увеличены: <code>set_time_limit(14400)</code> и <code>ini_set('memory_limit',  '2048M');</code>
  • 30 мая 2026 г. 12:01
Ответы на вопрос 1
Кратко — причиной обычно не сам Yii2, а то, как вы запускаете внешний процесс (FFmpeg) и/или системные лимиты: воркер очереди (или supervisor/systemd) может прерывать задачу по таймауту, PHP/Symfony Process может иметь таймаут по умолчанию, либо процесс убивает OOM‑killer. Что делать и как отладить:

1) Сбор логов и диагностика
- Логируйте stdout/stderr FFmpeg и код возврата. Это самое важное.
- Проверьте системные логи на предмет убийства процесса: dmesg | grep -i kill, dmesg | grep -i oom, /var/log/syslog, /var/log/messages.
- Проверьте логи Supervisor / systemd, в котором запущен воркер очереди (возможно, задачу принудительно останавливают).
- Посмотрите, не выходит ли задача за TTR очереди (yii2-queue имеет параметр ttr при push, и worker/driver может считать задачу «просроченной»).

2) Типичные причины и решения
- Symfony Process / PHP имеют таймаут. Убедитесь, что таймаут отключён:
  - Symfony Process: $process->setTimeout(null);
  - PHP CLI: set_time_limit(0) (вы уже ставили, но это не влияет на Symfony Process таймаут).
- Буферы stdout/stderr переполняются и процесс «зависает», если вы не читаете вывод. Читайте и/или перенаправляйте вывод в файл или лог.
- OOM‑killer: если ffmpeg требует много памяти, ядро может убить процесс. Проверьте dmesg, уменьшите потребление (меньше потоков: -threads N, lower presets), добавьте swap/увеличьте RAM.
- Лимиты ОС (ulimit) — проверьте ulimit -a для пользователя, под которым выполняется воркер.
- TTR/timeout очереди (yii2-queue): при публикации задания задаётся время резерва (ttr). Увеличьте его, чтобы job мог выполняться дольше.
- Supervisor/Systemd: настройте stopwaitsecs/Restart и др. Убедитесь, что не настроен «hard» timeout.

3) Пример корректного запуска FFmpeg в Yii2 Job (Symfony Process — читабельно и позволяет отключить таймаут, стримить вывод и получить код возврата):

Пример (внутри Job::execute() или handle()):
```
use Symfony\Component\Process\Process;
use Symfony\Component\Process\Exception\ProcessFailedException;

$cmd = [
    '/usr/bin/ffmpeg',
    '-i', $inputPath,
    '-c:v', 'libx264',
    '-preset', 'medium',
    '-crf', '23',
    '-c:a', 'aac',
    '-f', 'hls',
    '-hls_time', '10',
    '-hls_playlist_type', 'vod',
    $outputPlaylistPath,
];

$process = new Process($cmd);
$process->setTimeout(null); // отключаем таймаут
$process->setIdleTimeout(null); // на всякий случай

$process->run(function ($type, $buffer) use ($jobId) {
    // логируем прогресс в реальном времени, чтобы буферы не переполнялись
    if (Process::ERR === $type) {
        Yii::info("[FFMPEG ERR] $buffer", 'ffmpeg');
    } else {
        Yii::info("[FFMPEG OUT] $buffer", 'ffmpeg');
    }
});

if (!$process->isSuccessful()) {
    Yii::error('FFmpeg failed: ' . $process->getErrorOutput(), 'ffmpeg');
    throw new ProcessFailedException($process);
}
Yii::info('FFmpeg finished, exitcode=' . $process->getExitCode(), 'ffmpeg');
```

4) Если нужно, чтобы ffmpeg продолжал после завершения PHP (detach)
- Запускайте в фоне через nohup или systemd service:
  - exec("nohup /usr/bin/ffmpeg ... > /var/log/ffmpeg.log 2>&1 & echo $!");
  - Или порождайте отдельный systemd unit / transient service.
Но будьте осторожны: тогда воркер завершит задачу, не дождавшись результата — нужно синхронизировать статус.

5) Другие советы
- Ограничьте число потоков ffmpeg (-threads 1 или -threads N) если сервер одноядерный или память ограничена.
- Используйте прогрессивную загрузку и HLS параметры оптимально (-hls_flags delete_segments и др.) в зависимости от задачи.
- При больших входных файлах добавьте swap или увеличьте ресурсы VM, если OOM.
- Увеличьте параметр ttr при push в yii2-queue, например: Yii::$app->queue->push($job, $delay = 0, $ttr = 14400);

6) План действий для вас прямо сейчас
- Переключитесь на запуск ffmpeg через Symfony Process с setTimeout(null) и логируйте stderr.
- Запустите проблемное видео вручную в том же окружении (под тем же пользователем) из консоли — наблюдайте, завершится ли ffmpeg и какие сообщения будут в stderr/dmesg.
- Проверьте системные логи на OOM/kill и настройки supervisor/systemd, увеличьте ttr/timeout если надо.

Если пришлёте:
- Как именно вы запускаете ffmpeg сейчас (exec/shell_exec/proc_open/Symfony Process),
- конфигурацию очереди (какой driver yii2-queue, значение ttr),
- строки логов stderr ffmpeg и вывод dmesg при останове —
помогу точнее указать причину и корректный код.
Похожие вопросы