laravel的命令调度允许你在laravel命令中清晰流畅的定义。而且在使用调度程序时只需要在服务器上使用一条cron即可。调度在app\Console\kernel.php文件的schedule方法中定义。
启动调度
使用调度只需要将下面的cron项目加到服务器上。
* * * * * php /your-project/artisan schduel:run >> /dev/null 2>&1
上面的cron会每分钟调用一次laravel命令调度器。执行schedule:run命令时,laravel会根据你的调度运行预定任务。
定义调度
你可以在app\Console\kernel类的schedule方法中定义所有调度任务。
例:我们计划在午夜调用一个Closure。在Closure中执行数据库查询来清除一个表
<?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命令调度
除了consure调度,你还能调用Artisan命令和操作系统命令。举个例子,你可以给command方法传递命令名称或者类名称来调度一个Artisan命令。
$schedule->command("emails:send --force")->daily();
$chedule->command(EmailsCommand::class,['--force'])->daily();
队列调度任务
job方法可以用来进行队列调度。这个方法提供了一种快捷方式来调度任务,无需使用call方法手动创建闭包来调度任务。
$schedule->job(new Hertbeat)->everyFIveMinuites();
shell命令调度
exec可以用作向操作系统发出命令
$schedule->exec('node /home/forge/script.js')->daily();
调度频率设置
你可以为你的任务分配多种调度计划
方法 | 描述 |
->cron("* * * * *") | 在自定义的cron时间表上执行该任务 |
->everyMinute() | 每分钟执行一次任务 |
->everyFiveMinutes() | 每五分钟执行一次任务 |
->everyTenMinutes() | 每十分钟执行一次任务 |
->everyFiftenMinutes() | 每十五分钟执行一次任务 |
->everyThirtyMinutes() | 每半个小时执行一次任务 |
->hourly() | 每小时执行一次任务 |
->hourlyAt(17) | 每小时的17分钟执行一次任务 |
->daily() | 每天午夜执行一次任务 |
->dailyAt('13:00') | 每天13:00执行一次任务 |
->twiceDaily(1,13) | 每天1:00和13:00各执行一次任务 |
->weekly() | 每周执行一次任务 |
->monthly() | 每月执行一次任务 |
->monthlyOn(4,'13:00') | 每个月第四天13:00执行一次任务 |
->quarterly() | 每个季度执行一次 |
->yearly() | 每年执行一次 |
->timezone('China/Beijing') | 设置时区 |
这些方法可以合并其他限制条件以便生成更精确的调度。比如计划每周周一的调度
$schedule->call(function(){
})->weekly()->mondays()->at('13:00') //每周一的13:00运行
$schedule->commad('fool')->weekdays()
->hourly()
->timezone('Amarica/Chicago')
->between('8:00','17:00');//周一至周五上午8点至下午5点每个小时执行一次
以下时额外限制条件的列
方法 | 描述 |
->weekdays() | 将任务限在工作日 |
->sundays() | 将任务限在星期天 |
->mondays() | 将任务限在星期一 |
->tuesdays() | 将任务限在星期二 |
->wednesdays() | 将任务限在星期三 |
->thursdays() | 将任务限在星期四 |
->fridays() | 将任务限在星期五 |
->saturdays() | 将任务限在星期六 |
->between($start,$end) | 将任务限在开始到结束时间范围内 |
->when(closure) | 根据闭包函数的返回来限制任务 |
时间范围限制
between 方法可以用来限制一天中某个时间范围内的任务执行
$schedule->command(reminds:send'')
->hourly()
->between('7:00','20:00');
类似,unlessbetween()方法可以用来在一段时间范围内排除任务
$schedule->command('reminds:send')
->hourly()
->unlessbetween('23:00','4:00');
闭包测试限制
when方法可以用来根据给定的测试结果来限制任务的执行。换句话说,如果给定的closure返回true,那么如果没有其他约束条件阻止任务运行,任务就会执行。
$schedule->command('email:send')->daily()->when(function(){
return true;
});
skip可以看作时when的逆过程。如果skip返回true,则任务不执行。
$schedule->command('email:send')->daily()->skip(function(){
return true;
});
当链式调用多个when时,调度命令只有在所有的when条件都返回true时才会执行
避免任务重复
默认情况下,即便有相同的任务还在执行,调度内的任务依旧会被执行。为了避免这个问题,你可以使用withoutOverlapping()
$schedule->command('eamil:send')->withoutOverlapping();
在上面的例子中,如果没有其他Artisan命令 email:send在运行的话,此任务会每分钟执行一次。如果你的任务在执行时间上又很大不同,你无法准确确认你给定的任务需要多长时间,withoutOverlapping会有很大帮助
维护模式
当laravel处于维护模式时,laravel的调度功能将不会生效。然而如果你想在维护模式下强制执行任务你可以使用evenInmentenanceMode()
$schedule->command('Email:send')->evenInmentenanceMode();
任务输出
laravel调度器提供了几个方便调度任务生成的输出。首先,可是使用 sendOutputTo 方法将输出发送到单个文件上以便后续检查
$schedule->command('Email:send')->daily()->sendOutputTo($filePath);
如果想输出附加到指定文件上,则可以使用appendOutputTo方法
$schedule->command('Email:send')->appendOutputTo($filePath);
使用emailOutputTo方法,将可以通过电子邮件将输出发送到你指定的邮箱地址。在发送任务输出之前,你需要先配置laravel的电子邮件服务
$schedule->command('Email:send')->sendOutputTo($filePath)->emailOutputTO('youemail@qq.com');
注意:emailOutputTo SendOutputTo appendOutputTo 方式时command才有的,不支持在call方法使用
任务钩子
通过before和after方法,来指定在调度任务之前或之后执行的命令
$schedule->command('email:send')
->daily()
->before(function(){
//任务开始之前
})
->after(function(){
//任务完成后
})
Ping 网址
使用pingBefore和thenPing方法,可以在任务执行之前和之后自动ping指定的URL。这个方法对通知外部服务(例如Laravel Envoyer)你的调度任务已经开始或已经已经完成执行很有用。
$schedule->command('email:send')->daily()
->pingbefore($url)
->thenPing($url)
无论使用pingBefore($url)还是thenPing($url),都需要Guzzle Http函数库支持。你可以使用composer将Guzzle函数库添加到你的项目中
composer require guzzlehttp/guzzle