【PHP】Laravelでタスクスケジューリングを実装する方法

対象バージョン: Laravel 13.x / PHP 8.3+(2026年時点のシリーズ基準)
一次ソース: Task Scheduling

定期実行したい処理があるとき、OS の cron にコマンドをひとつずつ書くと、管理が散らばりソース管理からも外れがちです。Laravel のタスクスケジューラは、アプリ内でスケジュールを定義し、サーバー側の cron は1行だけにする仕組みです。この記事では、なぜ使うか、どこに定義するか、どう起動するか、運用で押さえる注意点までを Laravel 13.x の公式手順に沿って整理します。

この記事で分かること

  • スケジューラを使う理由(cron 集約とソース管理)
  • Laravel 13.x での定義場所(routes/console.php と Schedule ファサード)
  • Artisan コマンド・クロージャの登録と頻度メソッド
  • 本番の cron(schedule:run)とローカルの schedule:work
  • タイムゾーン、withoutOverlapping、onOneServer などの運用上の注意

なぜタスクスケジューラを使うか

従来は「毎日メール送信」「毎時レポート生成」など、タスクごとにサーバーの crontab を編集する必要がありました。エントリが増えると、いつ何が動くかを追いにくく、デプロイや環境差分でも壊れやすくなります。

Laravel のスケジューラでは次のように分担します。

  • アプリ側: どのコマンドを、どの頻度で、どの条件で動かすかを PHP で定義する(ソース管理に乗る)
  • サーバー側: 毎分1回だけ php artisan schedule:run を叩く cron を1行置く

schedule:run が現在時刻を見て、今実行すべき定義だけを走らせます(Task Scheduling)。


対象バージョンと定義場所の変遷

本記事の前提は Laravel 13.x / PHP 8.3+ です。Laravel 13 は 2026年3月17日リリースの現行メジャーで、サポート表上 PHP 8.3〜8.5 を対象とします(Release Notes)。

Laravel スケジュールの主定義場所
10.x 以前 app/Console/Kernel.php の schedule メソッド
11.x / 13.x(現行) routes/console.php で Schedule ファサードを使う(公式の典型)

fresh な Laravel 13 スケルトンには app/Console/Kernel.php はありません。旧記事や古いチュートリアルで見かける Kernel の protected function schedule(...) は、現行の主経路ではありません。アップグレード直後に古い手順のまま書くと動かない・場所が無い、という状態になります。

コマンド定義だけを routes/console.php に残したい場合は、bootstrap/app.php の withSchedule クロージャでも定義できます。本記事は公式どおり routes/console.php + Schedule ファサード を主経路とします。


タスクスケジュールの定義

基本: routes/console.php

スケジュールはアプリケーションの routes/console.php に書きます。Artisan コマンドを毎日実行する最小例です。

<?php

use Illuminate\Support\Facades\Schedule;

Schedule::command('emails:send')->daily();

この例では、emails:send という Artisan コマンドを毎日(深夜)実行する定義です。コマンド自体は別途 php artisan make:command などで用意してください。クラス名で指定することもできます。

use App\Console\Commands\SendEmailsCommand;
use Illuminate\Support\Facades\Schedule;

Schedule::command(SendEmailsCommand::class, ['Taylor', '--force'])->daily();

クロージャで定義する

短い処理ならクロージャでも登録できます。

use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schedule;

Schedule::call(function () {
    DB::table('recent_users')->delete();
})->daily();

登録内容の確認

定義した一覧と次回実行予定は次で確認できます。

php artisan schedule:list

タスクの頻度

頻度はチェーンするメソッドで指定します。よく使う例です。

メソッド 意味(概要)
hourly() 毎時
daily() 毎日(深夜)
dailyAt('13:00') 毎日 13:00
weekly() 毎週
monthly() 毎月
everyFiveMinutes() 5分ごと
cron('* * * * *') 任意の cron 式

曜日・時間帯の制約も付けられます。

use Illuminate\Support\Facades\Schedule;

Schedule::command('foo')
    ->weekdays()
    ->hourly()
    ->timezone('Asia/Tokyo')
    ->between('8:00', '17:00');

公式ドキュメントには秒単位を含む多数の頻度オプションがあります(Schedule Frequency Options)。入門では hourly / daily / weekly / monthly から始め、必要に応じて細かくすれば十分です。


タスクスケジューラの起動

本番: cron に1行

サーバーの crontab に、毎分 schedule:run を実行するエントリを追加します。タスクごとの cron は不要です。

* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1

/path-to-your-project は実際のプロジェクトルートに置き換えてください。この1行が動いていれば、アプリ内の定義に従って必要なタスクだけが実行されます。

ローカル開発: schedule:work

ローカルに本番と同じ cron を置く必要は通常ありません。代わりにフォアグラウンドでスケジューラを回すコマンドがあります。

php artisan schedule:work

終了するまで毎分(サブ分タスクがあればその間隔でも)スケジューラを評価します。動作確認や開発中の手動実行に使います。


運用で押さえる注意点

タイムゾーン

タスク単位でタイムゾーンを指定できます。

Schedule::command('report:generate')
    ->timezone('Asia/Tokyo')
    ->at('2:00');

アプリ全体の既定は config/app.php の schedule_timezone でも設定できます。サマータイムのあるタイムゾーンでは、実行が二重になったり欠けたりすることがあるため、公式は可能な範囲でタイムゾーン指定を避けることを勧めています。

重複実行の防止(withoutOverlapping)

既定では、前回の実行が終わっていなくても次の実行が始まり得ます。実行時間が読めないタスクには withoutOverlapping を付けます。

Schedule::command('emails:send')->withoutOverlapping();

ロックの有効期限(分)を引数で渡せます。ロックが残った場合は php artisan schedule:clear-cache でクリアできます(通常はサーバー障害などで固まったとき用)。

複数サーバーで1回だけ(onOneServer)

スケジューラを複数台で動かしていると、同じタスクが台数分実行されます。1台だけにしたい場合は onOneServer を使います。

Schedule::command('report:generate')
    ->fridays()
    ->at('17:00')
    ->onOneServer();

利用にはキャッシュドライバが database / memcached / dynamodb / redis のいずれかで、全サーバーが同じ中央キャッシュを共有している必要があります。クロージャを onOneServer する場合は name(...) で一意名を付けます。

そのほか(必要になったら)

  • runInBackground: 同時刻の複数タスクを並列寄りに走らせたいとき(command / exec のみ)
  • メンテナンスモード: 既定ではメンテ中はスキップ。強制するなら evenInMaintenanceMode
  • 失敗時フック: onFailure や emailOutputOnFailure で通知・後処理

詳細は公式の Task Hooks / Task Output を参照してください。


まとめ

Laravel 13.x では、スケジュールを routes/console.php の Schedule ファサード で定義し、サーバーには schedule:run の cron を1行 置く、というのが基本形です。頻度メソッドで実行タイミングを決め、ローカル確認には schedule:work、一覧確認には schedule:list を使います。重複防止や複数サーバー制限は、本番運用に入ってから必要に応じて足せば十分です。

旧バージョンの app/Console/Kernel.php の schedule メソッドは、現行 fresh 環境の主経路ではない点だけは混同しないようにしてください。

定期実行する Artisan コマンドの振る舞いをテストで固めたいときは、Laravelでテストを実装する方法で Feature / Unit テストの進め方を整理しています。

コメントする