在 Laravel 5.5 框架中使用计划任务

最近在用 Laravel 5.5 做的 YunLoad 项目中需要有一个提交任务自动截止功能需要用到计划任务,任务逻辑是在每天凌晨检查一次添加的提交任务是否已经过期,若已过期则自动将提交任务标记为 “已过期”.
Google 了很久也没能发现一个完整的教程,Laravel 相关文档也写得含糊其词,遂记录一下我的操作过程.

创建 Command

作为计划任务,我们需要的是 command(而不是网上说的 console),相关命令如下:

1
$ php artisan make:command CheckDeadline

此时会在 /app/Console/Commands/ 下创建一个 CheckDeadline.php 文件,我们需要在这个文件的 handle 函数中定义我们的需要的操作,如果代码设计 Model 操作的话需要在文件顶部声明(本例中需要 use Carbon\Carbon),部分代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
...
protected $signature = 'CheckDeadline:checkdeadline';// Define the Command name
...
public function handle()
{
// Get the non-ended courses as $courses array
foreach($courses as $course){
// $dl for Parse the course setted deadline
if($dl->isPast()){
// Mark the Course ended, update database...
$this->info('Course'.$course->id.'hitted deadline, ended.');
}
}
}

在 Console Kernel 中注册这个 Command

/app/Console/Kernel.php 中注册这个 Commmand,部分代码如下:

1
2
3
protected $commands = ['\App\Console\Commands\CheckDeadline',];
protected function schedule(Schedule $schedule)
{$schedule->command('checkdeadline')->daily();}

其中 daily() 表示每天凌晨执行,更多频率关键词可以参考 官方文档.

写好了之后我们测试一下:

1
2
3
➜ php artisan CheckDeadline:checkdeadline
Course 6 hitted deadline, ended.
Course 13 hitted deadline, ended.

跑起来了,看来没问题,我们把代码部署到服务器上面去并让他自己定期跑~

让系统的 crontab 定期拉起 Laravel

在部署好了相关文件后我们需要用 Linux 的 crontab 定期拉起 Laravel 来让 artisan 去执行我们的计划任务,新建个计划任务,然后如下编写:

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

需要注意的是,这里的 PHP 需要写绝对路径,如果不清楚的话建议先 whereis php 之后确认一下,比如我本地实验环境:

1
2
3
4
5
➜ whereis php
php: /usr/bin/php /usr/lib64/php /etc/php.ini /etc/php.d /usr/share/php /usr/share/man/man1/php.1.gz
➜ /usr/bin/php --version
PHP 7.1.16 (cli) (built: Mar 28 2018 07:11:55) (NTS)
...

那就需要写成(假设项目在 / var/www/yunload 下)

1
* * * * * /usr/bin/php /var/www/yunload/artisan schedule:run >> /dev/null 2>&1

2018-05-30 更新:似乎按照上面得写法 Laravel 调用的 command 时用的 artisan 不是绝对路径,这样会失败,目前我使用的方法如下:

1
@hourly /usr/bin/php /var/www/yunload/artisan CheckDeadline:checkdeadline >> /dev/null 2>&1

不过我有一个疑问,Wordpress 中可以定时自动发布文章,我们在安装 Wordpress 的时候并不需要利用系统的 crontab,那它们是如何实现的呢?或者说,为什么 Laravel 就必须要用系统 crontab 才能实现计划任务呢?

参考资料

  1. Laravel 5.5 - Task Scheduling With Cron Job Example - Laravelcode
  2. Task Scheduling - Laravel - The PHP Framework For Web Artisans

我的博客使用了Disqus评论框,如果你看不到评论框,那么多半Disqus服务在你所在的地区被墙,请使用代理访问。