PHP가있는 Apache 웹 서버 (서버는 Ubuntu)에서 실행되는 Yii 2 Framework를 사용하여 웹 응용 프로그램을 만듭니다.exec()는 비동기이어야하지만 그렇지 않습니다.
앱의 대부분은 사용자가 비디오를 업로드하는 것과 관련이 있습니다.이 비디오는 FFMpeg를 통해 두 번 다시 저장되고 한 번 MP4로, 다시 한번 WEBM으로 다시 실행됩니다. 또한 FFMpeg는 프레임을 추출한 다음 Imagick을 통해 정확하게 크기가 조정됩니다.
모든 작업에 상당한 시간이 걸리기 때문에 사용자에게 로딩 화면을 5 ~ 10 분 동안 표시하는 대신 콘솔 명령에 모든 처리를 넣고 비동기 적으로 실행합니다. 배경을 표시하고 동영상 처리가 완료되면 이메일로 보냅니다.
가 여기에 업로드 양식 모델의 관련 부분 :
// if the new database entry successfully saved
if($video->save()){
// define the target filename and full target filepath
$target_name = uniqid();
$target_path = Yii::getAlias('@webroot'). '/videos/' . $target_name;
// get the current working directory (should be /models)
$cwd = getcwd();
// move up one directory to the app base
chdir('../');
// prepare the shell command to process the video
$command = escapeshellcmd("php yii video/process " . $fileFullPath . " " . $target_name . " " . $target_path . " " . $video->id . " " . $video->name . " " . Yii::$app->language . " " . Yii::$app->homeUrl . " " . $this->email . " >/dev/null 2>&1 &");
// execute the shell command
exec($command);
// change the working directory back to the original
chdir($cwd);
// return the ID of the uploaded video
return $video->id;
}
쉘 명령의 끝에서, 당신은 PHP를 허용하는 명령을 비동기 적으로 실행하도록해야한다는/dev/null로 리디렉션을 볼 수 있습니다 스크립트를 계속 진행하고 업로드 된 비디오 ID를 컨트롤러로 반환하십시오.
다음은 동영상 컨트롤러 방법 actionProcess의 다소 단축 버전 : 당신이, 내가 FFMPEG를 호출하기 위해 PHP-는 FFmpeg 라이브러리 (https://github.com/PHP-FFMpeg/PHP-FFMpeg)를 사용하고 말할 수있을 것으로
public function actionProcess($source_path, $target_name, $target_path, $id, $first_name, $language, $homeUrl, $email)
{
$ffmpeg = FFMpeg\FFMpeg::create(['timeout' => 7200, 'ffmpeg.threads' => 4]);
$video = $ffmpeg->open($source_path);
$dimension = new FFMpeg\Coordinate\Dimension(1280, 1280);
$video
->filters()
->resize($dimension, 'inset')
->synchronize();
$video
->frame(FFMpeg\Coordinate\TimeCode::fromSeconds(2))
->save($target_path . '.png');
$video
->save(new FFmpeg\Format\Video\X264(), $target_path . '.mp4')
->save(new FFMpeg\Format\Video\WebM(), $target_path . '.webm');
@unlink($source_path);
$image = Imagick::open($target_path . '.png');
//////////
// There's a big if statement here controlling whether to crop the image vertically or horizontally to get the desired size.
// Didn't seem necessary to include.
//////////
$image->saveTo($target_path . '.png');
$video = Video::find()->where(['id' => $id])->one();
$video->path = $target_name;
$video->published = Video::IS_PUBLISHED;
$video->save();
//////////
// There's another large code block here to send an email to the user.
// Also didn't seem necessary to include.
//////////
return 0;
}
, 그리고 난 Imagick을 구현하기 위해 tpmanc의 Yii2 Imagick 라이브러리 (https://github.com/tpmanc/yii2-imagick)를 사용하십시오.
그렇다면 exec() 명령은 비동기 적으로 구현되어야하지만 그렇지 않습니다. 비디오를 업로드하면 비디오가 업로드되고 비디오 처리가 끝나기 전에 5-10 분 정도 기다렸다가 마침내 '성공적으로 업로드 된'페이지가로드됩니다.
여기에 문제가 있습니다. 작동했습니다. 개발주기 초기에 테스트 해 보았습니다. 그런 다음 쉘 명령에서/dev/null 리디렉션을 주석 처리하여 개발 중에 디버깅 할 수있게되었습니다. 이제는 다시 추가 했으므로 더 이상 작동하지 않는 것 같습니다. 위 명령이 비동기 적으로 실행되지 않도록 할 수 있습니까?
EDIT : 콘솔 스크립트가 실행 한 PHP 스크립트에만 변경 사항을 추가해야합니다. 실행될 때와 실행되지 않을 때 사이에 실제 명령 자체 (업로드 양식 모델)를 실행하는 스크립트는 변경되지 않았습니다. 그래서 내가 놓친 분명한 오타가 있거나 콘솔 명령에서/dev/null 리다이렉션을 무시하고 스크립트가 끝날 때까지 기다릴 양식 모델을 강요합니다. 실제로는 가능한 것처럼 보이지 않습니다. , 물론 그 카운트에 잘못 될 수 있습니다.
업데이트 : 비디오를 업로드 할 때마다 수동으로 스크립트를 호출하는 대신 Cron을 사용하여 스크립트를 호출합니다. 즉, 실제 질문이 아직 해결되지 않은 채로이 질문을 공개해야한다고 생각합니다. 위의 exec()가 비동기 적으로 실행되지 않는 이유는 무엇입니까?
최종 수정 : 웰프, 여기에 downvote 요정이 와서. 닫힌 질문을 생각해보십시오.
* "명령을 비동기 적으로 실행해야하는/dev/null 리디렉션을 볼 수 있습니다"*. 좀 빠지는. 명령 끝 부분에있는 앰퍼샌드는 백그라운드에서 명령을 실행하도록 * shell *에 지시합니다. 백그라운드 작업을 수행하려는 경우 Celery와 같은 실제 비동기 작업 대기열을 사용해야합니다. –