はじめに

管理画面で何かしらのデータをCSVファイルのアップロードによってインポートする機能を作りました。データの件数によっては処理に時間がかかってしまうので、インポート処理はジョブ化して非同期で実行するようにしました。

use App\Http\Requests\CsvRequest;
use App\Jobs\ImportFromCsvJob;

class ImportController extends Controller
{
    public function importCsv(CsvRequest $request)
    {
        $path = $request->csv->store('csv');
        ImportFromCsvJob::dispatch(auth()->user(), $path);

        $request->session()->flash('success', '作成処理を開始しました。終了したらメールで通知します。');

        return back();
    }
}

このように、コントローラー側でアップロードされたファイルを保存して、そのパスをジョブに渡します。ジョブ側では受け取ったパスをStorage::get()で読み込んでインポート処理を行います。

ローカル環境で確認して問題なかったので検証用環境にデプロイしたのですがインポートされませんでした。調べてみると、ジョブ側で File not found となっていました。

検証用環境

検証用環境はDokkuというHerokuライクなツールで構築しています。詳しい設定内容は省略しますが、Procfileにて

web: vendor/bin/heroku-php-apache2 public/
worker: php artisan queue:work --tries=3

となっていて、管理画面とキューワーカがそれぞれ実行されています。

原因と対応

管理画面とキューワーカはそれぞれ別のコンテナとなります。なのでwebにアップロードしたファイルがworkerには存在しませんでした。

# 検証用環境にて
$ dokku enter app-name web # webコンテナに入る
$ ls storage/app
アップロードしたファイルが表示される
$ exit
$ dokku enter app-name worker # workerコンテナに入る
$ ls storage/app
アップロードしたファイルは表示されない
$ exit

ストレージプラグインを使ってコンテナ間で共有できるストレージを設定しました。

$ dokku storage:mount app-name /path/to/shared-storage:/app/storage/app
$ dokku ps:rebuild app-name

これでインポート処理が行われるのを確認しました。

Laravelで、と書きましたがLaravel関係なかったです。仮想環境での問題なので、Herokuでも同様の対応が必要になると思われます。