laravel-任务调度
开头先说一下平时在项目中定时任务的写法:平时我们如果需要定时地去更新或执行一些操作,我们是通过写crontab去调用php脚本、shell脚本等定时去完成指定操作,例如这样
但是带来的一个问题就是 当项目比较多的时候,各个项目的定时任务都怼在一起,你很难区分这些定时任务,再者,添加多个定时任务需要你去频繁的利用ssh登录服务器去添加crontab任务,很是让人头疼;而在laravel中 框架就提供了任务调度器去系统且优雅地进行任务调度,我们只需要每分钟去执行框架的
schedule:run
命令即可,它每分钟会去扫描你的定时操作并定期执行,具体调用操作如下
定义调度
你只需要在app/Console/Kernel的schedule方法中去定义需要执行的操作即可,比如:下面的操作
你可以像上面的例子一样调用artisancommand去执行操作
也可以去调用像这样的闭包去执行
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方法,你可以指定在调度任务完成之前和之后要执行的代码:
$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文件中,是这样的一段代码:
/** * 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中
/**
* 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);
}
这里拿前台执行来说明
/**
* 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命令
/**
* 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