1
/
5

【開発日誌#30】LaravelでQueue(キュー)を用いた、大容量CSVをダウンロードする方法 S3にファイルを保存 URLをメールで送信

【はじめに】

今回は、LaravelでQueueを用いてCSVファイルをS3へ保存、そして保存先のURLをメールで送信する実装を行ないました。その方法をご紹介させていただきます。

この記事では、

  • Queueの設定
  • CSVのファイルを作成
  • CSVをS3に保存
  • S3の保存先のURLを作成
  • 作成したURLをMailで送信
  • Jobの設定

を組み合わせて利用する方法をまとめています。

【Queueの仕組み】

Queue(キュー)とは

データ構造の一つで、処理の”待ち行列”を実現する際によく使われます。要素を入ってきた順に一列に並べ、先に入れた要素から順に取り出すという規則で出し入れを行う、先入先出のデータ構造です。

Job(ジョブ)とは

処理そのものです。QueueにJobが登録され、QueueにあるJobが実行されます。

Dispatch(ディスパッチ)とは

job(ジョブ)をqueue(キュー)に送ることです。

Worker(ワーカー)とは

Jobを実行する役割です。

【背景】

今回はすでに、CSVダウンロードが実装されている状態からの改修作業でした。

参照元のテーブルレコード数が多くなったときに、ダウンロード実行に時間が掛かってしまい、タイムアウトでダウンロードができないという問題が発生したため、対策を行いました。

【作業内容】

タイムアウトの対策として、Queueを使用して、CSV作成をバックグラウンドで処理、S3に保存。S3の保存先のURLをメールで送信しました。

ユーザーは、メールで送られたURLから、生成済みのCSVをダウンロードするため、タイムアウトが解消され、無事にダウンロードを実行できました。


☆ポイント☆

Queueによるバックグラウンド処理を用いて、タイムアウトを解消したことです。

なぜ、タイムアウトにならないのか?

Queueにより非同期処理を行うため、処理が分かれるためです。

非同期処理について、次のイメージをご覧ください。

非同期処理は、タスクを実行中にその処理を中断することなく、別のタスクを実行できます。

今回の場合、ダウンロードボタンを押すとタスク1とタスク2が実行されます。

次のイメージをご覧ください。

  • タスク1 「ダウンロードありがとうございます。CSVダウンロードリンクをメールで送信しました。」と表示(処理時間が短い)
  • タスク2 バックグラウンドでCSV作成(処理時間が長い)

ユーザー表示はタスク1で、処理時間が短いため、タイムアウトエラーにならない、ということになります。

注意点として、CSV作成をQueueで処理する場合、バックグラウンドで処理されるため、最後のダウンロードまでできないです。

そのため、タスク2(バックグラウンド)でCSV作成の後どうするか、指示をしてあげる必要があります。

今回は、保存先のURLをMailで送信するという対応を行なっています。

【実装内容】

作業手順です。

1:Queueの設定
2:CSVのファイルを作成
3:CSVをS3に保存
4:S3の保存先URLを作成
5:作成したURLをMailで送信する
6:Jobの設定

この流れで進めることにします。

※今回は改修作業でしたので、2:CSVのファイルを作成、S3の接続設定は割愛します。


■対象ファイル

各々の作業環境によってファイル名は異なりますが、今回の対象ファイルを参考に記載します。

  • app/Service/ProjectService.php (function applicantsDownload)
  • app/Http/Controllers/ProjectController.php (function applicantsDownload)
  • app/Mail/CsvDownloadMail.php
  • resources/views/csv_download.blade.php
  • app/Jobs/CsvCreate.php

■関係図

Jobの実行ファイルと、Job本体のファイルがあります。

Job本体の中に、CSV ・S3へ保存・メール内容などを記載します。


1:Queueの設定

Queueの設定方法はいくつかありますが、今回はDatabaseを用いた方法をご紹介します。

・Queue用のテーブル作成

ターミナルで下記コマンドの実行

php artisan queue:table
php artisan migrate

Queue用の jobsテーブル と

キューの実行失敗時に使用される failed_jobsテーブルが作成されます。


・Jobクラス作成

ターミナルで下記コマンドの実行

php artisan make:job CsvCreateJob

実行すると、app/Jobsファルダに、CsvCreateJob.phpが作成されます。

ここに、Job処理を記載します。


・envの設定

.envを下記で設定

QUEUE_CONNECTION=database
QUEUE_DIRVER=database

Queueは、デフォルトでは同期処理です。

非同期処理にするために上記設定を行います。


2:CSVのファイルを作成

この部分は割愛させていただきます。今回は、PHPで実装していますが、

”Laravel Excel”というライブラリーを用いると、比較的シンプルに作成できます。


3:CSVをS3に保存

下記をCSV作成を実装しているファイルに記載します。

今回は、ProjectService.php の function applicantsDownload に記載します。

下記コードで、ストレージのapp/applicants_csv/{$fileName}にファイルを保存します。

Storage::disk('local')->put('applicants_csv/' . $fileName, '');

下記コードで、S3の applicants_csv/{$fileName}に、ストレージの app/applicants_csv/{$fileName}にあるファイルを保存しています。

Storage::disk('s3')->put('applicants_csv/' . $fileName, file_get_contents(storage_path('app/applicants_csv/' . $fileName)));


4:S3の保存先URLを生成

下記コードを、CSV作成を実装しているファイルに記載します。

今回は、ProjectService.php の function applicantsDownload に記載します。

return Storage::disk('s3')->temporaryUrl('applicants_csv/' . $fileName, now()->addDay());

このコードは、S3保存先のURLを返します。

temporaryUrlは、S3ドライバーを使用して保存されたファイルへの、有効期限付きURLを作成できる便利なメソッドです。now()->addDay()で有効期限を1日に設定しています。

注意点として、ファイル保存先がlocalの場合、エラーになってしまうので、保存先がS3の場合に、使用可能です。


5:生成したURLをMailで送信する

ターミナルで下記コードを実行し、app/Mailに CsvDownloadMail.phpを作成します。

php artisan make:mail CsvDownloadMail

CsvDownloadMailに、下記コードを記載します。

$urlを受け取り、使用します。

protected $url;protected $url;
public function __construct($url)
{
    $this->url = $url;
}

下記コードで、メールの中身を設定

public function build()
    {
        return $this->subject('件名')
        ->view('emails.csv_download')  //メール本文のview
        ->with(['url' => $this->url]); //メール本文にurlを渡す
    }


6:Jobの設定

Jobの実行ファイルに下記コードを記載します。

今回は CsvCreate.php に記載します。 

$projectId, $searchを受け取り使用

protected $projectId;
protected $search;
public function __construct($projectId, $search)
{
    $this->projectId = $projectId;
    $this->search = $search;
}

下記コードで、Jobの実行を行います。

今回は、ProjectController.php に記載します。

この引数を実行ファイル(CsvCreate.php)の引数と合わせます。

CsvCreate::dispatch($projectId, $search);


今回は、applicantsDownloadで、

  • CSVファイル作成
  • CSVをS3に保存
  • S3の保存先URLを生成

を実装しています。

CsvCreate.phpでは、

  • applicantsDownload
  • CsvDownloadMailを作成して、送信

を実行しています。

public function handle(ProjectService $projectService)
{
    $project = Project::find($this->projectId);

    $url = $projectService->applicantsDownload($this->projectId, $this->search);

    try {
        Mail::to($project->login_mail_address)->send(new CsvDownloadMail($url, $project->name));
    } catch (Exception $e) {
        Log::error(__CLASS__ . ' メール送信に失敗', ['exception' => $e->getTrace()]);
    }
}

これで、実装完了です。

【まとめ】

いかがでしたでしょうか。今回は、Queueによる非同期処理を用いて、時間が掛かる処理をバックエンドで行う方法をご紹介しました。この手法は、CSV作成以外にも、さまざまなユースケースで活用できます。

この記事があなたの開発に少しでも役立てば幸いです。

株式会社コムデからお誘い
この話題に共感したら、メンバーと話してみませんか?
株式会社コムデでは一緒に働く仲間を募集しています
5 いいね!
5 いいね!

同じタグの記事

今週のランキング

三枝 右弥さんにいいねを伝えよう
三枝 右弥さんや会社があなたに興味を持つかも