LaravelからPythonを利用する場合おすすめの手法

カンナートのエンジニアチームに所属しているOAと申します。

この記事では、とある案件にてPythonソースをLaravelに組み込む必要がでたとき得た知見を紹介いたします。

目次:

 ・要約

    ・PythonをLaravelで利用したい場合、どう実装するか?

 ・なぜProcessコンポーネントを勧めるのか?

 ・ソースコード解説

 ・サーバーデプロイ後のトラブルシューティングに役立ちそうなリスト(Python + Laravelに限る。)

 

要約:

主張:LaravelからPythonを利用する場合、Symfonyに付属しているProcessコンポーネントを利用するのがおすすめです。ProcessFailedExceptionが非常に優秀です。

公式ドキュメント

インストール:

自分が利用したソース例:

注意点:

pythonファイルを実行する場合、例えばコマンドラインからは

としている場合、例えば

とフルパスで指定する。

 

PythonをLaravelで利用したい場合、どう実装するか?:

自分なりに色々調べた結果、

「Python実行ファイルをLaravel内部に仕込んでおき、PHP内部でPython実行コマンドを呼び出す」結論に至りました。

Pythonで実行した結果を返すAPI専用プロジェクトを作成し、別サーバーにおく案もありましたが、

納期的に数日レベルだったのと、お客様があまりコストをかけたくないのとで、工数が少なそうなPython組み込み方式を選択した次第です。

 

なぜProcessコンポーネントを勧めるのか?:

結論からいうと、「PHPの組み込み関数群よりエラーハンドリングが優秀だから」です。

PHPにはコマンドをプログラム実行時に実行できるexecsystemといった関数が標準で存在しますが、

エラーがでたとき値を返さないときがある、try~catchで拾えないときがある、という不便さを持ちます。

execを例にProcessと比較してみます。

シナリオ:

①pythonソースで外部モジュールをimportし利用している。各環境ではpip3 install hogehogeなどで持ってくる必要がある。

十分デバッグしている。

単体の実行結果:

Laravel上での処理:

実行後ログ:

②ローカル環境で動くことが確認できたのでサーバー(AWS EC2など)にデプロイした。

③事象:execを実行してもなにも返ってこない。

「なにも返ってこない」ので切り分け作業の量と時間がともに増えます。

エラーメッセージは役立たないときもありますが、問題の切り分けをするとき役立つことが多いです

エラーメッセージが欲しいのでLaravelソースを下記のように変更します。

実行後、ログにはたとえば(下記は正確ではありません)

とpython側のエラーが表示されます。

以上から、原因として「サーバーデプロイ後、hogehogeライブラリをインストールしてないことが原因だった」とわかります。

このように、「呼び出したソースで発生したエラーを吐き出してくれる」という強力な機能を持ちます。

補足:「十分にデバッグしている」前提があると書いてあるくせになぜPythonソース側のエラーを吐き出してくれるものを勧めるのか?という疑問はごもっともです。デバッグでは自分の認識外はカバーできません。この認識外を少しでも出すのに役立つので紹介しております。

 

ソースコードの解説:

$process = new Process([]) :

Processの中にはarrayでコマンドを渡します。

ls -la であれば [‘ls’, ‘-la’]

python3 process.pyであれば[‘python3’, ‘process.py’]

など。

もしpythonが動かない場合、フルパスを渡すと良いです。

また、arrayに分割してパックするのが面倒な場合、下記の書き方でも代用可能です。

ちゃんとCLIなどで実行して動くと確認したものを入れると良いです。

$process->mustRun():

公式だと

The mustRun() method is identical to run(), except that it will throw a Symfony\Component\Process\Exception\ProcessFailedException if the process couldn’t be executed successfully (i.e. the process exited with a non-zero code):

とあるように、ProcessFailedExceptionを投げるために必要です。

本記事の肝とも言えます。

$process->getOutput():

実行結果を取得できます。

pythonでいえばprint(‘hogehoge’)と書いた個所をCLIなどで表示される個所を取得できます。

上記でいうhogehogeです。

$process->getMessage():

例外がキャッチされ、どんなエラーが出たのか見たいとき利用します。

Laravelであれば

とでも書いてstorage/logs/laravel.log(デフォのパス)などに出力すると良いかと思います。

本記事の第二の肝です。

 

サーバーデプロイ後チェックリスト(Python + Laravelに限る。):

python3系(or2系)をインストールしているか

pipなどで必要なライブラリをインストールしているか

python3ならばpip3 install hogehogeと書いてインストールしたか

python自体へのパスを取得したか。

python実行ファイルへのフルパスを取得したか。

(手っ取り早いのはサーバー上で該当ファイルの存在するディレクトリでpwdコマンドの結果をコピペ)

 

以上となります。

ちなみに「pip周りはshell scriptで持っておいて一緒に環境に持って行けよ・・・」というツッコミはごもっともです。

 

良い開発ライフをお送りください。

Share on Facebook0Tweet about this on TwitterShare on Google+0Email this to someone