2016-12-11 27 views
1

Yii 2 Frameworkを使用してWebアプリケーションを作成しています。Apache Webサーバー上でPHPを実行しています(サーバーはUbuntuです)。exec()は非同期でなければなりませんが、

アプリの大きな部分は、ユーザーがビデオをアップロードすることです。そのビデオはFFMpegを介して2回、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をコントローラに返します。あなたが伝えることができるかもしれませんが、私は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; 
} 

は、ここでのVideoController法actionProcessのやや短縮バージョンですImagickを実装するためにtpmancのYii2 Imagickライブラリ(https://github.com/tpmanc/yii2-imagick)を使用します。

したがって、exec()コマンドは非同期に実装されるべきですが、そうではありません。ビデオをアップロードすると、ビデオがアップロードされ、ビデオ処理が完了してから最後に「正常にアップロードされました」ページがロードされるまで、さらに5〜10分間待機します。

ここが問題です:それは働いていました。私は開発サイクルの早い段階でそれをテストしました。次に、シェルコマンドの/ dev/nullリダイレクトをコメントアウトして、開発中にデバッグできるようにしました。今度はそれを追加したので、もう動作していないようです。上記のコマンドが非同期に実行されない原因は何ですか?

EDIT:唯一の変更は、コンソールで実行されたPHPスクリプトに加えられたものです。実際のコマンド自体を実行するスクリプト(アップロードフォームモデル)は、スクリプトが動作したときと実行されなかったときの間で変更されませんでした。だから私は紛れているかのような明らかなタイプミスがあるか、コンソールコマンドの何かが/ dev/nullのリダイレクトを無効にして、スクリプトが完了するのを待つようにフォームモデルを強制します。もちろん、私はその数に間違っている可能性があります。

更新:ビデオをアップロードするたびに手動でスクリプトを呼び出すのではなく、これを達成するためにCronを使用して巻き上げました。つまり、実際の質問はまだ解決されていないので、この質問はまだ開いておくべきだと思います。なぜ、上記のexec()が非同期で実行されないのでしょうか?

最終編集:Welp、ここでdownvoteの妖精が来る。閉じた質問を考えてみましょう。

+0

* "コマンドを非同期で実行させるはずの/ dev/nullリダイレクトを見ることができます" *。まあまあ。コマンドの末尾にあるアンパサンドは、バックグラウンドでコマンドを実行するように* shell *に指示します。バックグラウンドタスクを実行する場合は、Celeryのような実際の非同期タスクキューを使用する必要があります。 –

答えて

1

私はビデオで数年前に同じ問題を抱えています。 PHPは非同期ではありません。 React PHP(http://reactphp.org/)を使うか、これを処理するためにJobQueueやCronタスクリストを作成することをお勧めします。ビデオを作成し、アップロードして、ビデオ、ショーメッセージ、「レンダリング」をユーザに表示し、サムネイルを作成していないときにビデオにサンプルサムネイルを作成することができます。

私はYiiをJobQueueに使用してこの例を作成しましたが、後で検索が改善されました。 https://github.com/yiisoft/yii2-queue

+0

事は、これは前に_すでに働いています。私はフレームワークが事実であることを知る前に(以前は明らかでした)、私が以前に「生の」PHPで作ったYii 2のアプリケーションを作り直しています。それがうまくいくと、Yiiが何らかの形で干渉しない限り、ここでは動作しないことがわかります。それを除いて、最近は3〜4日ほど前にYiiで働いていました。 – CGriffin

関連する問題