Laravel入坑指南(番外)——任务调度

Laravel提供了非常强劲的命令行工具(如果还不了解,传送到第8往篇),我们如果想要定期执行某个命令行,可以利用crontab进行定时设置。如果有多个定期的任务,很简单,我们设定多条crontab规则在不同时间段内调度不同的命令即可。

而Laravel框架内部也提供了这样的调度机制。(当然,还是逃不过crontab的支持)

 

首先,我们需要在crontab中添加这么一条规则

* * * * * php /path-to-your-project/artisan schedule:run >> /dev/null 2>&1

 

 

其次,所有的调度任务都在/app/Console/Kernel.php的schedule函数中进行调度设置

 

 

这个函数中可以调度闭包、可调用对象(包含__invoke的对象)、artisian命令、列队任务以及shell命令。以下以例子进行说明:

//调度闭包,->daily()即调度选项,每天凌晨零点运行任务
//关于调度选项后面会统一说明
$schedule->call(function () {
    DB::table('recent_users')->delete();
})->daily();


//调度可调用对象
//DeleteRecentUsers类中包含了__invoke魔术方法
$schedule->call(new DeleteRecentUsers)->daily();


//调度artisian命令
$schedule->command('emails:send --force')->daily();
$schedule->command(EmailsCommand::class, ['--force'])->daily();


//调度列队任务
$schedule->job(new Heartbeat)->everyFiveMinutes();
$schedule->job(new Heartbeat, 'heartbeats')->everyFiveMinutes();    //将job投递到heartbeats列队中


//调度shell命令
$schedule->exec('node /home/forge/script.js')->daily();

常用的调度选项:

方法 描述
->cron('* * * * *'); 在自定义Cron调度上运行任务
->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(); 每年运行一次
->timezone('America/New_York'); 设置时区

 

额外调度约束选项:

方法 描述
->weekdays(); 只在工作日运行任务
->weekends(); 只在周末运行任务
->sundays(); 每个星期天运行任务
->mondays(); 每个星期一运行任务
->tuesdays(); 每个星期二运行任务
->wednesdays(); 每个星期三运行任务
->thursdays(); 每个星期四运行任务
->fridays(); 每个星期五运行任务
->saturdays(); 每个星期六运行任务
->between($start, $end); 基于特定时间段运行任务
->when(Closure); 基于特定测试运行任务
->environments($env); 只在指定环境运行任务

 

举几个例子:

// 每周星期一13:00运行一次...
$schedule->call(function () {
    
})->weekly()->mondays()->at('13:00');


// 工作日的上午8点到下午5点每小时运行...
$schedule->command('foo')
         ->weekdays()
         ->hourly()
         ->timezone('America/Chicago')
         ->between('8:00', '17:00');


//每天7点到22点之间,每小时运行
$schedule->command('reminders:send')
         ->hourly()
         ->between('7:00', '22:00');


//每天23点到4点之外的时间内,每小时运行
$schedule->command('reminders:send')
         ->hourly()
         ->unlessBetween('23:00', '4:00');


//when的闭包返回true时运行
$schedule->command('emails:send')->daily()->when(function () {
    return true;
});


//skip的闭包返回false时运行
$schedule->command('emails:send')->daily()->skip(function () {
    return true;
});

 

 

第三,任务调度的重叠处理

当下一次任务开始执行时,万一上一次的任务还没有执行完成,新的任务是会执行的。也就是说,有可能出现多次任务重叠执行的情况。

为了避免这种情况,我们可以使用外部的手段来加锁,比如文件锁flock,或者redis的setnx都可以。但是Laravel非常贴心,已经帮我们准备了这样的机制:

$schedule->command('emails:send')->withoutOverlapping();    //锁默认24小时失效

$schedule->command('emails:send')->withoutOverlapping(10);    //锁10分钟失效

 

 

第四,任务调度的顺序

默认情况下,同时调度的多个命令会顺序执行。如果你有一些长时间运行的命令,将会导致随后的命令在预期之后很久才能执行。如果你想要让命令在后台执行以便它们可以同时运,可以使用 runInBackground 方法来实现:

$schedule->command('analytics:report')
     ->daily()
     ->runInBackground();

 

 

第五,任务输出

我们可以将任务中的输出重定向覆盖写入或追加写入文件中,便于问题的排查:

//覆盖写入
$schedule->command('emails:send')
     ->daily()
     ->sendOutputTo($filePath);

//追加写入
$schedule->command('emails:send')
     ->daily()
     ->appendOutputTo($filePath);

 

 

最后,任务钩子

使用 before 和 after 方法,你可以指定在调度任务完成之前和之后要执行的代码:

$schedule->command('emails:send')
         ->daily()
         ->before(function () {
             // 任务即将开始...
         })
         ->after(function () {
             // 任务已经完成...
         });

 

 

好了,Laravel话题到这里正式结束了。关于Laravel还有一些知识点,如果想要深入了解的小伙伴就去看官方文档吧。

下周开始,博主会进入另一个话题。至于要写什么,嗯,还没想好,大家下周再见:)

 

 

---------------------------  我是可爱的分割线  ----------------------------

最后博主借地宣传一下,漳州编程小组招新了,这是一个面向漳州青少年信息学/软件设计的学习小组,有意向的同学点击链接,联系我吧。

 

posted on 2020-08-07 21:36  咚..咚  阅读(929)  评论(0编辑  收藏  举报

导航