イントロダクション
コンソールコマンドを一つ一つスケジュールするため、今まで開発者はCronエントリーを毎回作成してきました。しかしこれは悩みの種でした。コンソールの実行スケジュールはソース管理されていませんでしたし、Cronのエントリを追加するためにその都度SSHでサーバーに接続する必要がありました。人生をより簡単に生きましょう。Laravelコマンドスケジューラーを使い、サーバーにCronエントリーを一つ追加するだけで、他に何も用意しなくてもLaravelだけでコマンド実行スケジュールをスラスラと記述的に定義することができます。
コマンドスケジュールはapp/Console/Kernel.php
ファイルに記述します。このクラスの中にschedule
メソッドが見つかるでしょう。始めやすいように、このメソッドの中に簡単な例を準備してあります。好きなだけジョブスケジュールをSchedule
オブジェクトに追加してください。
スケジューラーを使いはじめる
唯一以下のCronエントリーだけ、サーバーに追加してください。
* * * * * php /path/to/artisan schedule:run >> /dev/null 2>&1
このCronエントリは、Laravelコマンドスケジューラーを毎分呼び出します。それにより、Laravelはスケジュールされているジョブを評価し、実行する必要のあるジョブを起動します。これ以上簡単にできません!
スケジュール定義
スケジュールタスクは全部App\Console\Kernel
クラスのschedule
メソッドの中に定義します。手始めに、スケジュールタスクの例を見てください。この例は毎日深夜12時に「クロージャー」をスケジュールしています。「クロージャー」の中でテーブルをクリアするデータベースクエリーを実行しています。
<?php
namespace App\Console;
use DB;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* アプリケーションで提供するArtisanコマンド
*
* @var array
*/
protected $commands = [
\App\Console\Commands\Inspire::class,
];
/**
* アプリケーションのコマンド実行スケジュール定義
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
protected function schedule(Schedule $schedule)
{
$schedule->call(function () {
DB::table('recent_users')->delete();
})->daily();
}
}
「クロージャー」の呼び出しをスケジュールするほかにArtisanコマンドとオペレーティングシステムコマンドを実行できます。例としてArtisanコマンドをスケジュールするcommand
メソッドを使ってみましょう。
$schedule->command('emails:send --force')->daily();
オペレーティングシステムでコマンドを実行するためにはexec
メソッドを使います。
$schedule->exec('node /home/forge/script.js')->daily();
繰り返しのスケジュールオプション
もちろん、タスクは様々なスケジュールを割り付けることができます。
メソッド | 説明 |
---|---|
->cron('* * * * * *'); |
CRON記法によるスケジュール |
->everyMinute(); |
毎分タスク実行 |
->everyFiveMinutes(); |
5分毎にタスク実行 |
->everyTenMinutes(); |
10分毎にタスク実行 |
->everyThirtyMinutes(); |
30分毎にタスク実行 |
->hourly(); |
毎時タスク実行 |
->daily(); |
毎日深夜12時に実行 |
->dailyAt('13:00'); |
毎日13:00に実行 |
->twiceDaily(1, 13); |
毎日1:00と13:00時に実行 |
->weekly(); |
毎週実行 |
->monthly(); |
毎月実行 |
->yearly(); |
毎年実行 |
これらのメソッドは週の特定の曜日だけに実行させるために、追加の制約と組み合わせ細かく調整できます。
$schedule->call(function () {
// 週に一回、月曜の13:00に実行…
})->weekly()->mondays()->at('13:00');
以下が追加のスケジュール制約のリストです。
メソッド | 説明 |
---|---|
->weekdays(); |
ウイークデーのみに限定 |
->sundays(); |
日曜だけに限定 |
->mondays(); |
月曜だけに限定 |
->tuesdays(); |
火曜だけに限定 |
->wednesdays(); |
水曜だけに限定 |
->thursdays(); |
木曜だけに限定 |
->fridays(); |
金曜だけに限定 |
->saturdays(); |
土曜だけに限定 |
->when(Closure); |
クロージャの戻り値がture の時のみに限定 |
真値テスト制約
when
メソッドは指定した真値テストの結果に基づき制限を実行します。言い換えれば指定した「クロージャー」がture
を返し、他の制約が実行を停止しない限りタスクを実行します。
$schedule->command('emails:send')->daily()->when(function () {
return true;
});
when
メソッドをいくつかチェーンした場合は、全部のwhen
条件がtrue
を返すときのみスケジュールされたコマンドが実行されます。
タスク多重起動の防止
デフォルトでは以前の同じジョブが起動中であっても、スケジュールされたジョブは実行されます。これを防ぐには、withoutOverlapping
メソッドを使用してください。
$schedule->command('emails:send')->withoutOverlapping();
この例の場合、emails:send
Artisanコマンドは実行中でない限り毎分実行されます。withoutOverlapping
メソッドは指定したタスクの実行時間の変動が非常に大きく、予想がつかない場合に特に便利です。
タスク出力
Laravelスケジューラーはスケジュールしたタスクが生成する出力を取り扱う便利なメソッドをたくさん用意しています。最初にsendOutputTo
メソッドを使い、後ほど内容を調べられるようにファイルへ出力してみましょう。
$schedule->command('emails:send')
->daily()
->sendOutputTo($filePath);
出力を指定したファイルに追加したい場合は、appendOutputTo
メソッドを使います。
$schedule->command('emails:send')
->daily()
->appendOutputTo($filePath);
emailOutputTo
メソッドを使えば、選択したメールアドレスへ出力をメールで送ることができます。最初にsendOutputTo
メソッドを使い、ファイルへ出力しておく必要があることに注意してください。また、タスクの出力をメールで送る前に、Laravelのメールサービスの設定を済ませておく必要もあります。
$schedule->command('foo')
->daily()
->sendOutputTo($filePath)
->emailOutputTo('foo@example.com');
注意:
emailOutputTo
とsendOutputTo
メソッドはcommand
メソッド専用で、call
メソッドはサポートしていません。
タスクフック
before
とafter
メソッドを使えば、スケジュールされたタスクの実行前後に指定したコードを実行することができます。
$schedule->command('emails:send')
->daily()
->before(function () {
// タスク開始前…
})
->after(function () {
// タスク終了後…
});
URLへのPing
pingBefore
とthenPing
メソッドを使用し、タスク実行前後にに指定したURLへ自動的にPingをることができます。これはLaravel
Envoyerのような外部サービスへスケジュールされたタスクが始まる、または完了したことを知らせるのに便利です。
$schedule->command('emails:send')
->daily()
->pingBefore($url)
->thenPing($url);
pingBefore($url)
かthenPing($url)
のどちらを使用するにも、Guzzle
HTTPライブラリーが必要です。Guzzleはcomposer.json
ファイルに以下の行を追加してプロジェクトに追加できます。
"guzzlehttp/guzzle": "~5.3|~6.0"