Laravel 8.x タスクスケジュール

イントロダクション

以前は、サーバでスケジュールする必要のあるタスクごとにcron設定エントリを作成する必要がありました。しかしながら、タスクスケジュールがソース管理されないため、これはすぐに苦痛になる可能性があります。既存のcronエントリを表示したり、エントリを追加したりするには、サーバへSSHで接続する必要がありました。

Laravelのコマンドスケジューラは、サーバ上でスケジュールするタスクを管理するための新しいアプローチを提供しています。スケジューラを使用すると、Laravelアプリケーション自体の中でコマンドスケジュールを流暢かつ表現力豊かに定義できます。スケジューラを使用する場合、サーバに必要なcronエントリは1つだけです。タスクスケジュールは、app/Console/Kernel.phpファイルのscheduleメソッドで定義されます。手を付けるのに役立つように、メソッド内に簡単な例が定義されています。

スケジュール定義

スケジュールするすべてのタスクは、アプリケーションのApp\Console\Kernelクラスのscheduleメソッドで定義します。はじめに、例を見てみましょう。この例では、毎日深夜に呼び出されるようにクロージャをスケジュールします。クロージャ内で、データベースクエリを実行してテーブルをクリアします。

<?php

namespace App\Console;

use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
use Illuminate\Support\Facades\DB;

class Kernel extends ConsoleKernel
{
    /**
     * アプリケーションで提供するArtisanコマンド
     *
     * @var array
     */
    protected $commands = [
        //
    ];

    /**
     * アプリケーションのコマンド実行スケジュール定義
     *
     * @param  \Illuminate\Console\Scheduling\Schedule  $schedule
     * @return void
     */
    protected function schedule(Schedule $schedule)
    {
        $schedule->call(function () {
            DB::table('recent_users')->delete();
        })->daily();
    }
}

クロージャを使用したスケジュールに加えて、呼び出し可能なオブジェクトをスケジュールすることもできます。呼び出し可能なオブジェクトは、__invokeメソッドを含む単純なPHPクラスです。

$schedule->call(new DeleteRecentUsers)->daily();

スケジュールしたタスクの概要と、次に実行がスケジュールされている時間を表示したい場合は、schedule:list Artisanコマンドを使用します。

php artisan schedule:list

Artisanコマンドのスケジュール

クロージャのスケジュールに加えて、Artisanコマンドおよびシステムコマンドをスケジュールすることもできます。たとえば、commandメソッドを使用して、コマンドの名前またはクラスのいずれかを使用してArtisanコマンドをスケジュールできます。

コマンドのクラス名を使用してArtisanコマンドをスケジュールする場合、コマンドが呼び出されたときにコマンドに提供する必要がある追加のコマンドライン引数の配列を渡せます。

use App\Console\Commands\SendEmailsCommand;

$schedule->command('emails:send Taylor --force')->daily();

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

キュー投入するジョブのスケジュール

キュー投入するジョブをスケジュールするには、jobメソッドを使います。このメソッドを使うと、ジョブをキューに入れるためのクロージャを自前で作成するcallメソッドを使わずとも、ジョブをスケジュール実行できます。

use App\Jobs\Heartbeat;

$schedule->job(new Heartbeat)->everyFiveMinutes();

オプションの2番目と3番目の引数をjobメソッドに指定して、ジョブのキューに入れるために使用するキュー名とキュー接続を指定できます。

use App\Jobs\Heartbeat;

// "sqs"接続の"heartbeats"キューにジョブをディスパッチ
$schedule->job(new Heartbeat, 'heartbeats', 'sqs')->everyFiveMinutes();

シェルコマンドのスケジュール

オペレーティングシステムでコマンドを実行するためにはexecメソッドを使います。

$schedule->exec('node /home/forge/script.js')->daily();

繰り返しのスケジュールオプション

指定間隔で実行するようにタスクを設定する方法の例をいくつか見てきました。しかし、タスクに割り当てることができるタスクスケジュールの間隔は他にもたくさんあります。

メソッド 説明
->cron('* * * * *'); カスタムcronスケジュールでタスクを実行
->everyMinute(); 毎分タスク実行
->everyTwoMinutes(); 2分毎にタスク実行
->everyThreeMinutes(); 3分毎にタスク実行
->everyFourMinutes(); 4分毎にタスク実行
->everyFiveMinutes(); 5分毎にタスク実行
->everyTenMinutes(); 10分毎にタスク実行
->everyFifteenMinutes(); 15分毎にタスク実行
->everyThirtyMinutes(); 30分毎にタスク実行
->hourly(); 毎時タスク実行
->hourlyAt(17); 1時間ごと、毎時17分にタスク実行
->everyTwoHours(); 2時間毎にタスク実行
->everyThreeHours(); 3時間毎にタスク実行
->everyFourHours(); 4時間毎にタスク実行
->everySixHours(); 6時間毎にタスク実行
->daily(); 毎日深夜12時に実行
->dailyAt('13:00'); 毎日13:00に実行
->twiceDaily(1, 13); 毎日1:00と13:00時に実行
->weekly(); 毎週日曜日の00:00にタスク実行
->weeklyOn(1, '8:00'); 毎週月曜日の8:00時に実行
->monthly(); 毎月1日の00:00にタスク実行
->monthlyOn(4, '15:00'); 毎月4日の15:00に実行
->twiceMonthly(1, 16, '13:00'); 毎月1日と16日の13:00にタスク実行
->lastDayOfMonth('15:00'); 毎月最終日の15:00時に実行
->quarterly(); 四半期の初日の00:00にタスク実行
->yearly(); 毎年1月1日の00:00にタスク実行
->yearlyOn(6, 1, '17:00'); 毎年6月1日の17:00にタスク実行
->timezone('America/New_York'); タスクのタイムゾーンを設定

これらの方法を追加の制約と組み合わせてると、特定の曜日にのみ実行する、さらに細かく調整したスケジュールを作成できます。たとえば、毎週月曜日に実行するようにコマンドをスケジュールできます。

// 週に1回、月曜の13:00に実行
$schedule->call(function () {
    //
})->weekly()->mondays()->at('13:00');

// ウィークエンドの8時から17時まで1時間ごとに実行
$schedule->command('foo')
          ->weekdays()
          ->hourly()
          ->timezone('America/Chicago')
          ->between('8:00', '17:00');

追加のスケジュール制約のリストを以下にリストします。

メソッド 説明
->weekdays(); ウィークデーのみに限定
->weekends(); ウィークエンドのみに限定
->sundays(); 日曜だけに限定
->mondays(); 月曜だけに限定
->tuesdays(); 火曜だけに限定
->wednesdays(); 水曜だけに限定
->thursdays(); 木曜だけに限定
->fridays(); 金曜だけに限定
->saturdays(); 土曜だけに限定
->days(array|mixed); 特定の日にちだけに限定
->between($startTime, $endTime); 開始と終了時間間にタスク実行を制限
->unlessBetween($startTime, $endTime); 開始と終了時間間にタスクを実行しないよう制限
->when(Closure); クロージャの戻り値がtrueの時のみに限定
->environments($env); 指定の環境でのみタスク実行を限定

曜日の限定

daysメソッドはタスクを週の指定した曜日に実行するように制限するために使用します。たとえば、日曜日と水曜日に毎時コマンドを実行するようにスケジュールするには次のように指定します。

$schedule->command('emails:send')
                ->hourly()
                ->days([0, 3]);

または、タスクを実行する日を定義するときに、Illuminate\Console\Scheduling\Scheduleクラスで使用可能な定数を使用することもできます。

use Illuminate\Console\Scheduling\Schedule;

$schedule->command('emails:send')
                ->hourly()
                ->days([Schedule::SUNDAY, Schedule::WEDNESDAY]);

時間制限

betweenメソッドは一日の時間に基づき、実行時間を制限するために使用します。

$schedule->command('emails:send')
                    ->hourly()
                    ->between('7:00', '22:00');

同じように、unlessBetweenメソッドは、その時間にタスクの実行を除外するために使用します。

$schedule->command('emails:send')
                    ->hourly()
                    ->unlessBetween('23:00', '4:00');

論理テスト制約

whenメソッドを使用して、特定の論理テストの結果に基づいてタスクの実行を制限できます。言い換えると、指定するクロージャがtrueを返す場合、他の制約条件がタスクの実行を妨げない限り、タスクは実行されます。

$schedule->command('emails:send')->daily()->when(function () {
    return true;
});

skipメソッドはwhenをひっくり返したものです。skipメソッドへ渡したクロージャがtrueを返した時、スケジュールタスクは実行されません。

$schedule->command('emails:send')->daily()->skip(function () {
    return true;
});

whenメソッドをいくつかチェーンした場合は、全部のwhen条件がtrueを返すときのみスケジュールされたコマンドが実行されます。

環境制約

environmentsメソッドは、指定する環境でのみタスクを実行するために使用できます(APP_ENV環境変数で定義されます。)

$schedule->command('emails:send')
            ->daily()
            ->environments(['staging', 'production']);

タイムゾーン

timezoneメソッドを使い、タスクのスケジュールをどこのタイムゾーンとみなすか指定できます。

$schedule->command('report:generate')
         ->timezone('America/New_York')
         ->at('2:00')

スケジュールされたすべてのタスクに同じタイムゾーンを繰り返し割り当てる場合は、App\Console\KernelクラスでscheduleTimezoneメソッドを定義することをお勧めします。このメソッドは、スケジュールされたすべてのタスクに割り当てる必要があるデフォルトのタイムゾーンを返す必要があります。

/**
 * スケジュールされたイベントで使用するデフォルトのタイムゾーン取得
 *
 * @return \DateTimeZone|string|null
 */
protected function scheduleTimezone()
{
    return 'America/Chicago';
}

Note: タイムゾーンの中には夏時間を取り入れているものがあることを忘れないでください。夏時間の切り替えにより、スケジュールしたタスクが2回実行されたり、まったくされないことがあります。そのため、可能であればタイムゾーンによるスケジュールは使用しないことを推奨します。

タスク多重起動の防止

デフォルトでは以前の同じジョブが起動中であっても、スケジュールされたジョブは実行されます。これを防ぐには、withoutOverlappingメソッドを使用してください。

$schedule->command('emails:send')->withoutOverlapping();

この例の場合、emails:send Artisanコマンドは実行中でない限り毎分実行されます。withoutOverlappingメソッドは指定したタスクの実行時間の変動が非常に大きく、予想がつかない場合にとくに便利です。

必要であれば、「重起動の防止(without overlapping)」ロックを期限切れにするまでに、何分間経過させるかを指定できます。時間切れまでデフォルトは、24時間です。

$schedule->command('emails:send')->withoutOverlapping(10);

単一サーバ上でのタスク実行

Note: この機能を利用するには、アプリケーションのデフォルトのキャッシュドライバとしてdatabasememcacheddynamodbredisキャッシュドライバを使用している必要があります。さらに、すべてのサーバが同じ中央キャッシュサーバと通信している必要があります。

アプリケーションのスケジューラを複数のサーバで実行する場合は、スケジュールしたジョブを単一のサーバでのみ実行するように制限できます。たとえば、毎週金曜日の夜に新しいレポートを生成するスケジュールされたタスクがあるとします。タスクスケジューラが3つのワーカーサーバで実行されている場合、スケジュールされたタスクは3つのサーバすべてで実行され、レポートを3回生成してしまいます。これは良くありません!

タスクをサーバひとつだけで実行するように指示するには、スケジュールタスクを定義するときにonOneServerメソッドを使用します。このタスクを最初に取得したサーバが、同じタスクを同じCronサイクルで他のサーバで実行しないように、ジョブにアトミックなロックを確保します。

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

バックグランドタスク

デフォルトでは、同時にスケジュールされた複数のタスクは、scheduleメソッドで定義された順序に基づいて順番に実行されます。長時間実行されるタスクがある場合、これにより、後続のタスクが予想よりもはるかに遅く開始される可能性があります。タスクをすべて同時に実行できるようにバックグラウンドで実行する場合は、runInBackgroundメソッドを使用できます。

$schedule->command('analytics:report')
         ->daily()
         ->runInBackground();

Note: runInBackgroundメソッドはcommandexecメソッドにより、タスクをスケジュールするときにのみ使用してください。

メンテナンスモード

アプリケーションがメンテナンスモードの場合、アプリケーションのスケジュールされたタスクは実行されません。これは、タスクがそのサーバで実行している未完了のメンテナンスに干渉することを望まないためです。ただし、メンテナンスモードでもタスクを強制的に実行したい場合は、タスクを定義するときにevenInMaintenanceModeメソッドを呼び出すことができます。

$schedule->command('emails:send')->evenInMaintenanceMode();

スケジューラの実行

スケジュールするタスクを定義する方法を学習したので、サーバで実際にタスクを実行する方法について説明しましょう。schedule:run Artisanコマンドは、スケジュールしたすべてのタスクを評価し、サーバの現在の時刻に基づいてタスクを実行する必要があるかどうかを判断します。

したがって、Laravelのスケジューラを使用する場合、サーバに1分ごとにschedule:runコマンドを実行する単一のcron設定エントリを追加するだけで済みます。サーバにcronエントリを追加する方法がわからない場合は、Laravel Forgeなどのcronエントリを管理できるサービスの使用を検討してください。

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

スケジュールをローカルで実行

通常、ローカル開発マシンにスケジューラのcronエントリを追加することはありません。代わりに、schedule:work Artisanコマンドを使用できます。このコマンドはフォアグラウンドで実行し、コマンドを終了するまで1分ごとにスケジューラーを呼び出します。

php artisan schedule:work

タスク出力

Laravelスケジューラはスケジュールしたタスクが生成する出力を取り扱う便利なメソッドをたくさん用意しています。最初にsendOutputToメソッドを使い、後ほど内容を調べられるようにファイルへ出力してみましょう。

$schedule->command('emails:send')
         ->daily()
         ->sendOutputTo($filePath);

出力を指定したファイルに追加したい場合は、appendOutputToメソッドを使います。

$schedule->command('emails:send')
         ->daily()
         ->appendOutputTo($filePath);

emailOutputToメソッドを使用して、選択した電子メールアドレスへ出力を電子メールで送信できます。タスクの出力をメールで送信する前に、Laravelのメールサービスを設定する必要があります。

$schedule->command('report:generate')
         ->daily()
         ->sendOutputTo($filePath)
         ->emailOutputTo('taylor@example.com');

スケジュールしたArtisanまたはシステムコマンドが、ゼロ以外の終了コードで終了した場合にのみ出力を電子メールで送信する場合は、emailOutputOnFailureメソッドを使用します。

$schedule->command('report:generate')
         ->daily()
         ->emailOutputOnFailure('taylor@example.com');

Note: emailOutputToemailOutputOnFailuresendOutputToappendOutputToメソッドは、commandexecメソッドに対してどれか一つしか指定できません。

タスクフック

beforeおよびafterメソッドを使用して、スケジュール済みのタスクを実行する前後に実行するコードを指定できます。

$schedule->command('emails:send')
         ->daily()
         ->before(function () {
             // タスクが実行されようとしている
         })
         ->after(function () {
             // タスクが実行された
         });

onSuccessメソッドとonFailureメソッドを使用すると、スケジュールされたタスクが成功または失敗した場合に実行されるコードを指定できます。失敗は、スケジュールされたArtisanまたはシステムコマンドがゼロ以外の終了コードで終了したことを示します。

$schedule->command('emails:send')
         ->daily()
         ->onSuccess(function () {
             // タスク成功時…
         })
         ->onFailure(function () {
             // タスク失敗時…
         });

コマンドから出力を利用できる場合は、フックのクロージャの定義で$output引数としてIlluminate\Support\Stringableインスタンスを型指定することで、afteronSuccess、またはonFailureフックでアクセスできます。

use Illuminate\Support\Stringable;

$schedule->command('emails:send')
         ->daily()
         ->onSuccess(function (Stringable $output) {
             // タスク成功時…
         })
         ->onFailure(function (Stringable $output) {
             // タスク失敗時…
         });

URLへのPing

pingBeforeメソッドとthenPingメソッドを使用すると、スケジューラーはタスクの実行前または実行後に、指定するURLに自動的にpingを実行できます。このメソッドは、Envoyerなどの外部サービスに、スケジュールされたタスクが実行を開始または終了したことを通知するのに役立ちます。

$schedule->command('emails:send')
         ->daily()
         ->pingBefore($url)
         ->thenPing($url);

pingBeforeIfおよびthenPingIfメソッドは、特定の条件がtrueである場合にのみ、特定のURLにpingを実行するために使用します。

$schedule->command('emails:send')
         ->daily()
         ->pingBeforeIf($condition, $url)
         ->thenPingIf($condition, $url);

pingOnSuccessメソッドとpingOnFailureメソッドは、タスクが成功または失敗した場合にのみ、特定のURLにpingを実行するために使用します。失敗は、スケジュールされたArtisanまたはシステムコマンドがゼロ以外の終了コードで終了したことを示します。

$schedule->command('emails:send')
         ->daily()
         ->pingOnSuccess($successUrl)
         ->pingOnFailure($failureUrl);

すべてのpingメソッドにGuzzle HTTPライブラリが必要です。Guzzleは通常、デフォルトですべての新しいLaravelプロジェクトにインストールされますが、誤って削除した場合は、Composerパッケージマネージャーを使用してプロジェクトへ自分でGuzzleをインストールできます。

composer require guzzlehttp/guzzle

ドキュメント章別ページ

ヘッダー項目移動

注目:アイコン:ページ内リンク設置(リンクがないヘッダーへの移動では、リンクがある以前のヘッダーのハッシュをURLへ付加します。

移動

クリックで即時移動します。

設定

適用ボタンクリック後に、全項目まとめて適用されます。

カラーテーマ
和文指定 Pagination
和文指定 Scaffold
Largeスクリーン表示幅
インデント
本文フォント
コードフォント
フォント適用確認

フォントの指定フィールドから、フォーカスが外れると、当ブロックの内容に反映されます。EnglishのDisplayもPreviewしてください。

フォント設定時、表示に不具合が出た場合、当サイトのクッキーを削除してください。

バックスラッシュを含むインライン\Code\Blockの例です。

以下はコードブロックの例です。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * ユーザに関連する電話レコードを取得
     */
    public function phone()
    {
        return $this->hasOne('App\Phone');
    }
}

設定を保存する前に、表示が乱れないか必ず確認してください。CSSによるフォントファミリー指定の知識がない場合は、フォントを変更しないほうが良いでしょう。

キーボード・ショートカット

オープン操作

PDC

ページ(章)移動の左オフキャンバスオープン

HA

ヘッダー移動モーダルオープン

MS

移動/設定の右オフキャンバスオープン

ヘッダー移動

T

最初のヘッダーへ移動

E

最後のヘッダーへ移動

NJ

次ヘッダー(H2〜H4)へ移動

BK

前ヘッダー(H2〜H4)へ移動

その他

?

このヘルプページ表示
閉じる