PHPで表を作りつつ、重い処理だけPythonに投げたいときのメモ。
前提の流れ
Blade のフォームでファイルアップロード → Python に投げる → 結果を Blade で表示。
3パターン
1. プロセス直呼び(同期)
Symfony Process で python3 script.py を叩いて stdout を JSON で受ける。一番シンプル。数秒で終わる処理ならこれで十分。
弱点は PHP-FPM のワーカーが Python の終了まで塞がること。長い処理でタイムアウトする。
$result = Process::run([$pythonBin, $script, $path]);
$data = json_decode($result->output(), true);
2. キュー + ジョブ(非同期)
呼び方は1と同じだが Laravel Queue に投げて非同期化。ブラウザには受付IDを即返し、ポーリングで結果を取りに行かせる。
数十秒〜数分の処理ならこれ一択。Redis + worker の運用コストがかかる。
非同期 = 「裏で処理して終わったら取りに行く」。リアルタイム垂れ流しではない。途中経過を流したいなら SSE / WebSocket は別の話。
3. FastAPI で常駐(HTTP)
Python 側を常駐サービスにして HTTP で叩く。フロントは PHP のままで、FastAPI は HTML を吐かない。JSON を返すだけの裏方。127.0.0.1 にバインドして外部から叩けないようにする。
$data = Http::post('http://127.0.0.1:8001/analyze', ['path' => $path])->json();
比較
| 毎回起動 | 常駐(FastAPI) | |
|---|---|---|
| 同期 | 1番。最小構成 | 軽い処理を高速に返す |
| 非同期 | 2番。重い処理向け | 重い処理 + モデル常駐 |
判断は「準備 : 処理」の比率で決まる。
| 準備 | 処理 | 選択 |
|---|---|---|
| 軽い | 短い | 1番 |
| 軽い | 長い | 2番 |
| 重い | 短い | 3番 |
| 重い | 長い | 3番 + 非同期 |
3番が要るのはどんなときか
常駐が効くのは「準備は重いのに処理は一瞬」のやつ。
モデル読み込み 20秒 + 判定 0.1秒 ← 常駐が刺さる
起動 0.5秒 + 分析 300秒 ← 常駐しても無意味
処理が長いやつほど常駐は意味がない。起動3秒なんて誤差だから。それは非同期の出番。
具体的に3番が要るのは、AIモデル(数百MB〜GB、ロード10〜30秒)、デカい辞書やベクトルインデックス、あとは高頻度リクエスト。
逆に、ファイル読んで集計、正規表現でパース、グラフ画像生成、外部API叩いて加工 — この辺は全部1番で足りる。
セッションなしで同時アクセスされたら混ざる?
混ざらない。受付IDが引換券になる。ジョブは DB に「ID / 状態 / 結果」で独立して1行ずつ保存されるので、自分の ID でしか結果を取れない。ログインもセッションも不要。
ID は URL に埋めておけばブラウザを閉じても後から見に来れる。ただし2点注意。
-
連番は絶対にやるな。
/result/1は他人の結果が見える。UUID v4 を使う - 掃除処理を最初から入れる。 会員制じゃないと誰も消しに来ないので溜まり続ける。24時間で結果とアップロードファイルを自動削除
worker が1つだと直列処理になる点も注意。並列にするなら queue:work を複数立てるが、CPU コア数が上限の目安。Python がメモリ食うなら無闇に増やすとサーバが死ぬ。
ハマりどころ
-
venv のパス — web サーバから実行されると PATH が違う。
python3ではなく/path/to/venv/bin/pythonをフルパスで config に持つ - ファイルの受け渡し — storage に保存してパスだけ渡す。標準入力に流し込むと大きいファイルで詰まる
- stdout と stderr を分ける — stdout は結果 JSON 専用。ログやエラーは stderr へ。混ぜると死ぬ
-
文字コード — Python 側で
encoding='utf-8'を明示。日本語ファイルで確実に事故る -
コマンドインジェクション — ユーザー入力を引数に直接渡さない。
Processの配列形式なら安全
結論
まず1番で作る。遅いと感じたら2番に移す。3番は Python 側が育ってから。
最初から3番をやると構成が重すぎる。ただし Python 側は def analyze(入力) -> 出力 の関数1本にまとめておくこと。これさえ守れば FastAPI で包むのは後から1時間で済む。
