laravel-任务调度
laravel schedule
开头先说一下平时在项目中定时任务的写法:平时我们如果需要定时地去更新或执行一些操作,我们是通过写crontab去调用php脚本、shell脚本等定时去完成指定操作,例如这样
但是带来的一个问题就是 当项目比较多的时候,各个项目的定时任务都怼在一起,你很难区分这些定时任务,再者,添加多个定时任务需要你去频繁的利用ssh登录服务器去添加crontab任务,很是让人头疼;而在laravel中 框架就提供了任务调度器去系统且优雅地进行任务调度,我们只需要每分钟去执行框架的schedule:run
命令即可,它每分钟会去扫描你的定时操作并定期执行,具体调用操作如下
定义调度
你只需要在app/Console/Kernel的schedule方法中去定义需要执行的操作即可,比如:下面的操作
你可以像上面的例子一样调用artisancommand去执行操作
也可以去调用像这样的闭包去执行
1
2
3
4
5
6
|
protected function schedule(Schedule $schedule)
{
$schedule->call(function () {
DB::table('recent_users')->delete();
})->daily();
}
|
亦或者直接用exec去执行系统脚本
$schedule->exec('node /home/forge/script.js')->daily();
调用脚本的频次
你可以用如下的框架命令去执行
方法 |
描述 |
->everyMinute(); |
每分钟运行一次任务 |
->everyFiveMinutes(); |
每五分钟运行一次任务 |
->everyTenMinutes(); |
每十分钟运行一次任务 |
->everyFifteenMinutes(); |
每十五分钟运行一次任务 |
->everyThirtyMinutes(); |
每三十分钟运行一次任务 |
->hourly(); |
每小时运行一次任务 |
->hourlyAt(17); |
每小时第十七分钟运行一次任务 |
->daily(); |
每天凌晨零点运行任务 |
->dailyAt(‘13:00’); |
每天13:00运行任务 |
->twiceDaily(1, 13); |
每天1:00 & 13:00运行任务 |
->weekly(); |
每周运行一次任务 |
->monthly(); |
每月运行一次任务 |
->monthlyOn(4, ‘15:00’); |
每月4号15:00运行一次任务 |
->quarterly(); |
每个季度运行一次 |
->yearly(); |
每年运行一次 |
也可以调用->cron去自定义执行时间(像这样20 0 * * *)
查看任务输出
为了方便查看调度任务的执行结果,平时我们是这样
去把执行结果在代码中输出 并把输出保存在日志文件中方便查看,laravel中我们可以用sendOutputTo将输出结果保存到指定文件或者用appendOutputTo追加输出结果到指定文件,甚至可以用emailOutputTo发送邮件通知某人执行结果
任务钩子
使用 before 和 after方法,你可以指定在调度任务完成之前和之后要执行的代码:
1
2
3
4
5
6
7
8
|
$schedule->command('emails:send')
->daily()
->before(function () {
# 任务即将开始...
})
->after(function () {
#任务已经完成...
});
|
还有像这样的操作
平时low一点的写法 你完全可以用if else去代替这里的操作,不过框架为我们提供了这样系统且优雅的写法
在框架中为:\vendor\laravel\framework\src\Illuminate\Foundation\Providers\ArtisanServiceProvider.php这个文件中会去注册框架自带的包括schedule:run的commands,
而scheduleRun的具体实现是在\vendor\laravel\framework\src\Illuminate\Console\Scheduling\ScheduleRunCommand.php文件中,是这样的一段代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
/**
* Execute the console command.
*
* @return void
*/
public function fire()
{
$eventsRan = false;
foreach ($this->schedule->dueEvents($this->laravel) as $event) {
if (! $event->filtersPass($this->laravel)) {
continue;
}
$this->line('<info>Running scheduled command:</info> '.$event->getSummaryForDisplay());
$event->run($this->laravel);
$eventsRan = true;
}
if (! $eventsRan) {
$this->info('No scheduled commands are ready to run.');
}
}
|
它会获取所有的event 并循环执行,像这样
event类在\vendor\laravel\framework\src\Illuminate\Console\Scheduling\Event.php中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
/**
* Run the given event.
*
* @param \Illuminate\Contracts\Container\Container $container
* @return void
*/
public function run(Container $container)
{
if ($this->withoutOverlapping &&
! $this->mutex->create($this)) {
return;
}
$this->runInBackground
? $this->runCommandInBackground($container)
: $this->runCommandInForeground($container);
}
|
这里拿前台执行来说明
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
/**
* Run the command in the foreground.
*
* @param \Illuminate\Contracts\Container\Container $container
* @return void
*/
protected function runCommandInForeground(Container $container)
{
$this->callBeforeCallbacks($container);
(new Process(
$this->buildCommand(), base_path(), null, null, null
))->run();
$this->callAfterCallbacks($container);
}
|
最后就是拿拼接的参数去组成crontab命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
/**
* Build the command for running the event in the foreground.
*
* @param \Illuminate\Console\Scheduling\Event $event
* @return string
*/
protected function buildForegroundCommand(Event $event)
{
$output = ProcessUtils::escapeArgument($event->output);
return $this->ensureCorrectUser(
$event, $event->command.($event->shouldAppendOutput ? ' >> ' : ' > ').$output.' 2>&1'
);
}
|
buildCommand的结果
还有一些部分没有介绍,可以参考http://laravelacademy.org/post/9000.html