WindowsでLaravelのスケジュールタスク設定(後編)
前回はwindowsでのスケジュールタスクの設定についてまとめました。後編ではスケジュールタスクの使い方について少し触れます。
スケジュールタスクを書く
公式では詳しい例が多いので、ここはよく使うスケジュールジョブのパターンを挙げます。
タスクはもちろん、同期処理のタスクでも良いし、非同期のものでも構いません。データ量が多い場合は基本的に非同期一択です。Laravelではジョブとの概念を抽象化して、非同期処理をジョブをディスパッチする形にまとめています。
まずはジョブをコマンドで作ります:
php artisan make:job ProcessSync
これでappのフォルダーにJobsのフォルダーが作られ、ジョブクラスのテンプレートが書き込まれます。その中、handleメソッドがジョブの実行時にコールされる関数となりますので、メインの処理は全部handleに書き込みます。ジョブにデータを引き渡したい場合、コンストラクターに定義できます。
class ProcessSync implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
private $log_msg;
private $system;
private $user_id;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct(String $system, int $user_id = 0)
{
$this->system = $system;
$this->user_id = $user_id;
$this->log_msg = '';
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
$log_id = $this->startLog($this->system);
$result = $this->syncWithSystem($this->system);
$this->updateLog($log_id, $result, $this->log_msg);
}
private function syncWithSystem(String $system)
{...}
private function startLog(String $system)
{...}
private function updateLog(int $log_id, bool $result, String $log_msg)
{...}
private getResult()
{...}
}
それでジョブをスケジュールに加えます。例えば、毎日の3回、8時間置きに実行したい時に、cron
メソッドを使います。他にもeveryMinute、every...、daily、dailyAt、などいっぱいありますので公式ドキュメントにご参照ください。細かく決めたいときは基本的にcronに頼ります。
class Kernel extends ConsoleKernel
{
protected $commands = [
//
];
protected function schedule(Schedule $schedule)
{
$schedule->job(new ProcessSync('1'))->cron('0 0,8,16 * * *');
}
protected function commands()
{
$this->load(__DIR__ . '/Commands');
require base_path('routes/console.php');
}
// 念のためタイムゾーンも
protected function scheduleTimezone()
{
return 'Asia/Tokyo';
}
}
補足ですが、ジョブはもちろんコントローラからもディスパッチは可能です。時には、実行の結果を引数として使いたい、という場合は、同期処理にすることで可能となります。
// とあるコントローラで
$job = new ProcessSync($system, $request->user->id);
$this->dispatch($job);
// 同期に処理したい場合
$this->dispatchNow($job);
$result = $job->getResult();
ジョブテーブルについて
ジョブについて一度変な「バグ」と会いました。databaseをデフォルトのジョブキューとして、ジョブのテーブルを作りました。しかし、テストするときに、ジョブテーブルに何のレコードも挿入されません。
ちょっと変だなと思って色々と調べましたが、どうやら、
-
jobsというテーブルは、QUEUE_DRIVER = database (設定済み)の場合のみ使用されます
-
dispatchが実行されるときに、jobsにレコードが挿入されます
-
ジョブが完了または失敗しましたら、レコードが削除されます(正直は残して欲しいですね、せめて残すかどうかを選択できるように)
-
そのため、今現在タスクキューにジョブが残っている(並んでいる)限り、jobsテーブルにレコードが見えます
検証するために、ワーカーを止めて何回かジョブをディスパッチすると、キューに溜まっていき、jobsテーブルにも見えてきます。それでphp artisan queue:work
でワーカーを立ち上げると、ジョブは消化されてしまい、またjobsが空に戻ります。
以上です。
Discussion