技術資料

Laravel 13のキューとキューワーカー入門:Apache環境で本番運用する方法

作成日:2026.08.16

Laravel 13でJobをキューへ登録する方法から、queue:listenとqueue:workの違い、--timeout=0の挙動までを解説します。Linux上のApache環境でWeb処理とキューワーカーを分離し、Supervisorでワーカーを常駐・再起動させる構成を中心に、Nginxやcronとの関係、デプロイ時のqueue:restartも整理します。

Laravelでは、CSVの読み込みやメール送信など、Webリクエストの中で実行すると時間がかかる処理をキューへ登録できます。

ただし、ジョブをキューへ登録しただけでは処理は実行されません。キューを監視してジョブを取り出すキューワーカーを起動しておく必要があります。

今回は、Laravel 13のキューワーカーについて、ローカル開発時の起動方法と、Linux上のApache環境へデプロイした後の動かし方を確認します。Nginxでもキューワーカーの考え方は同じですが、Webサーバーの設定例はApacheをメインにします。

Laravel 13の環境構築や画面表示については、以前のWindows 11でLaravel 13を始める記事で説明しました。今回はその続きとして、Webリクエストとは別に動く処理を追加します。また、MailpitでLaravelのメール送信を確認したメール送信の記事でもキュー送信に少し触れていますが、ここではキューワーカーの起動とデプロイ後の運用を中心に扱います。

前提

今回の前提環境は以下の通りです。

  • ローカル環境: Windows 11、PowerShell
  • デプロイ先: Linux系OS
  • Webサーバー: Apache HTTP Server
  • PHP実行環境: PHP-FPMおよびPHP CLI
  • Laravel Framework: 13.x
  • PHP: 8.3以上
  • プロセス監視: Supervisor

Laravel 13.xのサーバー要件には、PHP 8.3以上と、Ctype、cURL、DOM、Fileinfo、Mbstring、OpenSSL、PDO、Session、Tokenizer、XMLなどの拡張が含まれます。実際に使用するLinuxディストリビューションやPHPのパッケージ構成は環境によって異なるため、デプロイ前にLaravelのデプロイメントガイドでも確認してください。

ApacheのPHP-FPM連携やTLS証明書の設定は、すでに完了しているものとします。この記事では、Laravelアプリケーションとキューワーカーをどのように動かすかに範囲を絞ります。

キューとキューワーカーの役割

通常のWebリクエストでは、ブラウザからのリクエストを受け取ると、その処理が完了してからレスポンスを返します。処理の中で大きなファイルを読み込んだり、外部APIへ接続したりすると、レスポンスを返すまでに時間がかかります。

キューを使う場合は、Webリクエストの中で時間のかかる処理を直接実行せず、処理内容をジョブとしてキューへ登録します。リクエスト側は登録を終えた時点でレスポンスを返し、別のキューワーカーがキューからジョブを取り出して処理します。

ブラウザ
   |
   v
Apache + PHP-FPM -- ジョブをキューへ登録 --> キューの保存先
                                                    |
                                                    v
                                      Supervisor -- queue:work

ApacheとPHP-FPMはWebリクエストを処理します。一方、キューワーカーはPHP CLIで動作する別のプロセスです。Apacheが動いているだけでは、キューへ登録されたジョブは処理されません。Laravelのキュー接続やワーカーについては、Laravel公式のキューに関するドキュメントにも説明があります。

データベースキューを準備する

Laravelには、データベース、Redis、Amazon SQSなど複数のキュー接続が用意されています。今回は外部のキューサービスを追加せずに確認できるよう、データベースキューを例にします。

まず、プロジェクトの.envでキュー接続を確認します。

QUEUE_CONNECTION=database

データベースキューでは、ジョブを保存するjobsテーブルが必要です。プロジェクトにキュー用のMigrationがない場合は、次のコマンドで作成します。

php artisan make:queue-table
php artisan migrate

新しいLaravelプロジェクトには、キュー用のMigrationが最初から含まれている場合があります。その場合は、同じMigrationを重複して作成せず、database/migrationsを確認してからphp artisan migrateを実行します。

QUEUE_CONNECTIONsyncになっている場合、ジョブはキューへ保存されず、その場で実行されます。キューワーカーの動作を確認するときは、現在のキュー接続が意図したものになっているか確認してください。

Jobを作成してキューへ登録する

次に、キューへ登録されたメッセージをLaravelのログへ出力するJobを作成します。

php artisan make:job WriteQueueLog

作成されたapp/Jobs/WriteQueueLog.phpを、次のように編集します。

<?php

namespace App\Jobs;

use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
use Illuminate\Support\Facades\Log;

class WriteQueueLog implements ShouldQueue
{
    use Queueable;

    public function __construct(
        public string $message,
    ) {}

    public function handle(): void
    {
        Log::info('キューのJobを処理しました', [
            'message' => $this->message,
        ]);
    }
}

ShouldQueueを実装したJobは、通常のメソッド呼び出しとは異なり、dispatchメソッドで実行を依頼するとキューへ登録されます。ここでいう「ディスパッチ」は、Jobをキューへ送る処理のことです。handleメソッドは、キューワーカーがJobを取り出したときに実行されます。

今回はWeb画面にテスト用のURLを追加せず、TinkerからJobを登録します。

php artisan tinker
App\Jobs\WriteQueueLog::dispatch('キューの動作確認');

データベースキューを使用していれば、この時点ではhandleメソッドはまだ実行されません。jobsテーブルへジョブが登録され、キューワーカーが取り出すのを待っている状態です。

ローカルでキューワーカーを起動する

ローカルでキューワーカーを起動するには、プロジェクトのルートディレクトリでqueue:workを実行します。

php artisan queue:work

queue:workは、キューへ登録されたJobを処理し続ける長時間実行のコマンドです。先ほど登録したJobが処理されると、storage/logs/laravel.logへログが出力されます。

1件だけ処理して終了したい場合は、--onceを指定できます。

php artisan queue:work --once

キューワーカーを起動したままコードを変更した場合、queue:workは起動時に読み込んだアプリケーションの状態を保持するため、変更内容を自動的には読み込みません。ローカル開発でコード変更を反映しながら確認したい場合は、queue:listenを使う方法もあります。

php artisan queue:listen --tries=1 --timeout=0

queue:listenは、Jobごとにアプリケーションを読み込み直せる代わりに、queue:workより効率が低いコマンドです。開発時の動作確認には便利ですが、本番環境の常駐ワーカーには、通常queue:workを使います。両コマンドの違いは、Laravel公式のキューに関するドキュメントで確認できます。

--tries--timeout

--triesは、Jobを何回まで試行するかを指定するオプションです。--timeoutは、1回のJob処理を何秒まで許可するかを指定します。

--timeout=0と指定した場合は、0秒でタイムアウトするのではなく、Jobの実行時間によるLaravelのワーカーからの強制終了を無効にします。ただし、retry_afterの時間を超えると、処理中のJobが再取得される可能性があるため、本番環境ではJobの想定実行時間に合わせてタイムアウト値を設定します。

php artisan queue:work --tries=3 --timeout=60

タイムアウト値は、キュー接続のretry_afterより短くする必要があります。タイムアウト値の方が長いと、元のJobがまだ処理中なのに再試行され、同じJobが二重に処理される可能性があります。

Laravel 13の開発用devコマンドでは、既定のキュープロセスとしてqueue:listen --tries=1 --timeout=0が使われます。これは開発用の構成なので、これを本番環境の推奨設定としてそのまま使用しないようにします。

php artisan devcomposer run devの違い

Laravel 13には、ローカル開発に必要な複数のプロセスをまとめて起動するphp artisan devコマンドがあります。詳しくはLaravel公式のArtisan Consoleドキュメントを参照してください。既定では、次のプロセスを同時に起動します。

  • PHP開発サーバー
  • キューワーカー
  • ログ表示
  • Viteによるアセットの監視

Laravelの標準的なプロジェクトでは、Composerのdevスクリプトからこの開発処理を起動できます。プロジェクトを作成した直後であれば、Laravel公式のインストールガイドにあるように、次のコマンドを実行します。

npm install
npm run build
composer run dev

php artisan devがLaravel側のArtisanコマンドなのに対し、composer run devはプロジェクトのcomposer.jsonに定義されたComposerスクリプトを実行するコマンドです。標準構成では、ComposerスクリプトからLaravelの開発用プロセスを起動しますが、プロジェクトによってスクリプトの内容は変更できます。

Laravel 13.xの現行ドキュメントでは、php artisan devの実行にNode.js 22.13以上が必要とされています。Windowsではプロセス管理に別のパッケージが使われるため、node --versionとプロジェクトのpackage.jsonも確認してください。

これらはローカル開発を便利にするためのコマンドです。本番環境でWebサーバー、ログ表示、Vite、キューワーカーを一つのターミナルから起動し続ける用途には使いません。

ApacheでLaravelを公開する

ここからは、Linux上のApacheへLaravelアプリケーションを配置する例を確認します。Laravelのプロジェクト全体をWeb公開するのではなく、公開ディレクトリをpublicに限定します。

例えば、アプリケーションを次の場所へ配置したとします。

/var/www/example.com/current

ApacheのVirtualHostでは、DocumentRootをプロジェクトのpublicへ向けます。以下は設定の最小例です。PHP-FPMとの接続方法やモジュール名は、LinuxディストリビューションとPHPのバージョンに合わせて調整してください。Apacheのリクエスト書き換えについては、Apache HTTP Serverのmod_rewriteドキュメントも参照してください。

<VirtualHost *:80>
    ServerName example.com
    DocumentRoot /var/www/example.com/current/public

    <Directory /var/www/example.com/current/public>
        AllowOverride All
        Options -Indexes
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/example-error.log
    CustomLog ${APACHE_LOG_DIR}/example-access.log combined
</VirtualHost>

Laravelのpublic/.htaccessを利用する場合は、対象ディレクトリでAllowOverrideが許可されている必要があります。また、ApacheがPHP-FPMへPHPファイルを渡せる状態になっていることも確認します。

Laravelの公式デプロイメントガイドでも、アプリケーションの入口をpublic/index.phpへ限定するよう案内されています。プロジェクトのルートをそのまま公開すると、.envや設定ファイルなどが外部から参照される危険があります。

Laravelの書き込み権限

Laravelは、ログやキャッシュをstorageへ書き込みます。また、起動時にbootstrap/cacheへファイルを作成することがあります。ApacheのPHP-FPMプロセスと、Supervisorで起動するキューワーカーが、必要なディレクトリへ書き込める権限を持つようにします。

実行ユーザーやグループはサーバー構成によって異なります。www-dataを前提に固定せず、PHP-FPMの実行ユーザー、Supervisorのuser設定、デプロイユーザーの関係を確認してください。

Supervisorでキューワーカーを常駐させる

ApacheがWebリクエストを処理していても、キューワーカーは自動的には起動しません。Linuxの本番環境では、キューワーカーをプロセス監視ツールから起動します。

ここではSupervisorを使います。Laravel公式のキューワーカー設定例でもSupervisorが使われています。Ubuntu系の環境でパッケージを導入する例は次の通りです。パッケージ管理方法は、利用するLinuxディストリビューションに合わせて変更してください。

sudo apt-get install supervisor

Supervisorの設定ファイルを/etc/supervisor/conf.d/laravel-worker.confとして作成します。

[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=/usr/bin/php /var/www/example.com/current/artisan queue:work --sleep=3 --tries=3 --max-time=3600
directory=/var/www/example.com/current
autostart=true
autorestart=true
stopasgroup=true
priority=999
user=www-data
numprocs=1
redirect_stderr=true
stdout_logfile=/var/log/supervisor/laravel-worker.log
stopwaitsecs=3600

commandのPHPパス、Laravelプロジェクトのパス、userは、実際の環境に合わせて変更します。numprocs=1は1プロセスの例です。処理量に応じて増やす場合は、同じキューを複数のワーカーが処理することを前提に、Jobの重複実行や外部サービスの制限も確認します。

--max-time=3600は、ワーカーを1時間処理した後に終了させる指定です。Supervisorのautorestartによって再起動されるため、長時間動作したプロセスを定期的に入れ替えられます。長時間のJobを扱う場合は、stopwaitsecsが処理時間より短くならないようにします。

設定を読み込み、ワーカーを起動します。

sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start "laravel-worker:*"
sudo supervisorctl status

statusRUNNINGと表示され、ログファイルへワーカーの出力が記録されていれば、Supervisorからキューワーカーを起動できています。

Supervisorの設定は、Laravel公式のキューに関する資料にも例が掲載されています。実際には、Laravelプロジェクトの実行ユーザー、ログローテーション、プロセス数、停止待ち時間を環境に合わせて調整してください。

デプロイ後にワーカーを再起動する

queue:workは長時間実行されるため、起動後に更新したPHPコードを自動では読み込みません。新しいコードをデプロイした後は、ワーカーを再起動する必要があります。

Laravelでは、現在処理中のJobが終わってからワーカーを終了させるqueue:restartを実行できます。

cd /var/www/example.com/current
php artisan queue:restart

Supervisorがautorestart=trueでワーカーを監視していれば、ワーカーが終了した後に新しいプロセスを起動します。デプロイの一例は次のようになります。

cd /var/www/example.com/current
composer install --no-dev --optimize-autoloader
php artisan migrate --force
php artisan optimize
php artisan queue:restart

実際のデプロイでは、リリースディレクトリを切り替える方式や、メンテナンス時間を設ける方式などがあります。上のコマンドをそのまま全ての環境へ適用するのではなく、コードの配置、環境変数、データベースMigration、キャッシュ、ワーカー再起動の順序を採用しているデプロイ手順へ組み込んでください。

queue:restartはキャッシュへ再起動の合図を保存します。キャッシュ接続が正しく設定されていないと、ワーカーへ合図が届かない場合があります。

cronとLaravel Schedulerの違い

cronは、指定した時刻や間隔でコマンドを起動する仕組みです。Laravel Schedulerを使う場合は、Laravel公式のタスクスケジューリング資料にあるように、cronからLaravelのschedule:runを毎分実行します。

* * * * * cd /var/www/example.com/current && /usr/bin/php artisan schedule:run >> /dev/null 2>&1

Laravelはschedule:runの実行時刻を確認し、アプリケーションに定義されたスケジュールのうち、実行すべき処理だけを起動します。

一方、キューワーカーはキューへ登録されたJobを継続的に取り出すプロセスです。キューワーカーをcronで毎分起動すると、ワーカーが重複して起動したり、終了しないプロセスが残ったりする可能性があります。キューワーカーの常駐にはSupervisorなどのプロセス監視を使い、cronはSchedulerの実行に使う、というように役割を分けます。

スケジュールされた処理からJobを登録する構成もあります。その場合は、SchedulerがJobを登録する役割、キューワーカーがJobを処理する役割として、それぞれの実行状態を確認します。

Nginxを使う場合

Nginxを使う場合も、キューワーカーの起動とSupervisorの設定は基本的に同じです。変更するのは、WebサーバーのVirtualHostに相当するNginxのserver設定、PHP-FPMへの接続方法、ログ設定などです。

NginxのrootもLaravelプロジェクトのpublicへ向けます。Nginxの設定例は、Laravel公式のデプロイメントガイドに掲載されています。ApacheとNginxのどちらを使う場合も、プロジェクトのルートディレクトリ全体を公開しない点は共通です。

キューが処理されない場合の確認

QUEUE_CONNECTIONを確認する

QUEUE_CONNECTION=syncの場合は、Jobがキューへ保存されず、その場で処理されます。データベースキューを使う場合は、QUEUE_CONNECTION=databaseと、jobsテーブルを確認します。

環境変数を変更した後に設定キャッシュが残っている場合は、設定を確認してから必要に応じてキャッシュをクリアします。

php artisan config:clear
Supervisorの状態とログを確認する

Supervisorからワーカーが起動しているか確認します。

sudo supervisorctl status
sudo tail -f /var/log/supervisor/laravel-worker.log

ワーカーが停止している場合は、SupervisorのログとLaravelのstorage/logs/laravel.logを確認します。Jobの例外、PHP拡張の不足、環境変数、データベース接続、ファイル権限などを順番に切り分けます。

失敗したJobを確認する

失敗したJobをデータベースへ保存する構成では、queue:failedで一覧を確認できます。

php artisan queue:failed

原因を修正した後、対象のJobを再試行する場合は、一覧に表示されたIDを指定します。

php artisan queue:retry <job-id>

Jobが何度も失敗する場合は、単に再試行を繰り返すのではなく、例外の内容、入力データ、外部サービスの応答、Jobの冪等性を確認してください。

注意点

  • ApacheやNginxが起動していても、キューワーカーが起動しているとは限らない。
  • Laravelプロジェクトのルートではなく、publicだけをWeb公開する。
  • queue:listen --tries=1 --timeout=0は開発用の構成として扱い、本番用の設定へそのまま流用しない。
  • --timeoutretry_afterの関係を確認し、同じJobが二重に処理される設定を避ける。
  • Supervisorの実行ユーザーが、Laravelのログ、キャッシュ、キュー接続へアクセスできることを確認する。
  • Jobへ個人情報や秘密情報をそのまま渡さず、キューの保存先やログへ意図しない情報が残らないようにする。
  • 本番の.env、Supervisor設定、Apache設定へ、パスワードやAPIキーを直接記述して公開しない。

まとめ

Laravelのキューは、時間のかかる処理をWebリクエストから切り離すための仕組みです。Jobをキューへ登録した後、キューワーカーがJobを取り出して処理します。

ローカル開発では、queue:listencomposer run devを使って動作を確認できます。ただし、本番環境ではApacheやPHP-FPMとは別にqueue:workを起動し、Supervisorなどで常駐管理します。

デプロイ後はqueue:restartでワーカーへ新しいコードを読み込ませ、cronはLaravel Schedulerのschedule:run用に使います。Webサーバー、キューワーカー、プロセス監視、Schedulerを別の役割として整理すると、LaravelをApache環境へデプロイした後の動作を切り分けやすくなるかと思います。

この記事を書いた人

※上が私です。

奈良市を拠点に、27年以上の経験を持つフリーランスWebエンジニア、阿部辰也です。

これまで、ECサイトのバックエンド開発や業務効率化システム、公共施設の予約システムなど、多彩なプロジェクトを手がけ、企業様や制作会社様のパートナーとして信頼を築いてまいりました。

【制作会社・企業様向けサポート】
  • 専任エンジニアのいない企業様に対するシステム面の不安を解消
  • 柔軟な契約形態や短納期での対応により、急なニーズにも迅速にサポート
  • システムの企画段階から運用まで、ワンストップでのサービスを提供

Webシステムの開発やサイト改善でお困りの際は、どうぞお気軽にご相談ください。小さな疑問から大規模プロジェクトまで、最適なご提案を心を込めてさせていただきます。

ぜひ、プロフィールWeb制作会社様向け業務案内一般企業様向け業務案内もご覧くださいね。

Laravel 13でSQLiteを使ったCRUD入門:MigrationとEloquent Modelでmembersテーブルを操作する

2026.08.14

Laravel 13でSQLiteを設定し、Migrationでmembersテーブルを作成します。Eloquent ModelとLaravel Tinkerを使い、名前とメールアドレスの登録・取得・更新・削除を試します。

Laravel PHP SQLite

Windows 11でLaravel 13を始める:環境構築からルーティング・Controller・Bladeまで

2026.08.13

Windows 11にPHP、Composer、Laravel Installerを用意し、Laravel 13のプロジェクトを作成します。routes/web.php、Controller、Bladeの役割を説明し、最小構成のWebページを表示するまでの流れと、Windows環境でつまずきやすい点を紹介します。

Laravel PHP

Windows 11にMailpitを導入してLaravelのメール送信を確認する

2026.08.06

Windows 11にMailpitを導入し、Laravel 13からSMTPでテストメールを送信して、MailpitのWeb UIで受信内容を確認する手順を紹介します。設定キャッシュ、ポート競合、キュー送信、メールFakeとの使い分けについても説明します。

Laravel Mailpit PHP

MarkdownをHTMLへ変換する方法とXSS対策:PHP・JavaScript・Vue.jsの実装例

2026.08.12

PHP のleague/commonmarkと、Node.js のMarked・DOMPurifyを使い、MarkdownをHTMLへ変換する方法を紹介します。ユーザー入力やAI生成Markdownを未信頼入力として扱い、Vue.js のv-htmlへ安全に表示するための設定と注意点も整理します。

JavaScript PHP Vue.js

阿部辰也へのお仕事の依頼・お問い合わせ

軽いご相談もお気軽にどうぞ!

個人情報の取り扱いについて *必須 プライバシーポリシーをご確認いただき、同意いただける場合は「同意する」にチェックをしてください。

keyboard_double_arrow_up
TOP