2016-12-11 2 views
1

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 요정이 와서. 닫힌 질문을 생각해보십시오.

+0

* "명령을 비동기 적으로 실행해야하는/dev/null 리디렉션을 볼 수 있습니다"*. 좀 빠지는. 명령 끝 부분에있는 앰퍼샌드는 백그라운드에서 명령을 실행하도록 * shell *에 지시합니다. 백그라운드 작업을 수행하려는 경우 Celery와 같은 실제 비동기 작업 대기열을 사용해야합니다. –

답변

1

나는 몇 년 전에 비디오와 같은 문제가 있습니다. PHP는 비동기 적이 지 않습니다. React PHP (http://reactphp.org/)를 사용하거나 JobQueue 및/또는 Cron 작업 목록을 작성하여이 작업을 처리 할 것을 제안합니다. 동영상을 만들고 업로드하여 동영상을 보여주고 메시지를 표시하고 "렌더링"하고 미리보기 이미지를 만들지 않으면 동영상에 샘플 미리보기 이미지를 만들 수 있습니다.

나는 JobQueue에 Yii를 사용하여이 예제를 만들었지 만 나중에 더 잘 검색합니다. https://github.com/yiisoft/yii2-queue

+0

문제는 이전에 이미 작업했음을 의미합니다. 나는 이전에 '원시'PHP로 만들었던 Yii 2의 애플리케이션을 다시 만들었습니다. 프레임 워크가 사실이라는 것을 알기도 전에 (이것은 분명히 얼마 전이었습니다). 거기서 일하면 Yii가 어떤 방식 으로든 방해하지 않는 한 내가 여기에서 작동하지 않는 것을 볼 수있는 이유가 없습니다. 단, 3 일이나 4 일 전에는 Yii에서조차도 일하고있었습니다. – CGriffin

관련 문제