使用 Laravel 调度器的技巧
发布日期 作者 Paul Redmond
Laravel 的 任务调度 功能文档齐全,并提供流畅的 API,让您拥有 cron 的全部功能。文档涵盖了您快速上手调度器所需的大部分内容,但我想谈谈与 cron 相关的几个底层概念,这将有助于您更深入地了解 Laravel 如何确定哪些计划任务应该运行。
了解 Cron
在 Laravel 调度器的基础上,您需要了解如何通过 Cron 的有点让人困惑的语法在服务器上安排任务。
在我们更深入地了解 cron 并学习可以用来熟悉 cron 的资源之前,让我们先看看调度器的基本组成部分。
首先,您需要通过 Laravel 应用程序的 App\Console\Kernel::schedule()
方法定义计划任务
/** * Define the application's command schedule. * * @param \Illuminate\Console\Scheduling\Schedule $schedule * @return void */protected function schedule(Schedule $schedule){ // $schedule->command('inspire') // ->hourly();}
您可以使用此方法定义所有需要运行的计划任务。Schedule
实例方法 command()
返回 Illuminate\Console\Scheduling\Event
类的一个实例。
如果您想调试事件类的一个实例,您可以像以下示例一样进行转储
$event = $schedule->command('inspire') ->hourly(); dd($event->expression); // "0 * * * *"
要触发此方法,请运行 artisan
> php artisan"0 * * * *"
事件实例有一个 expression
属性,该属性在流畅的 API 调用之后存储任务的 cron 表示形式。
请记住此示例的值,因为我们将在下面讨论 cron。
Laravel 使用调度器的流畅 API(在本例中为 hourly()
方法)屏蔽了 cron,但了解 cron 将有助于您更好地理解幕后发生的事情。
以下文本表示应阐明 cron 的工作原理,如果您不熟悉(即使您熟悉,我认为这仍然有用)
# Use the hash sign to prefix a comment# +---------------- minute (0 - 59)# | +------------- hour (0 - 23)# | | +---------- day of month (1 - 31)# | | | +------- month (1 - 12)# | | | | +---- day of week (0 - 7) (Sunday=0 or 7)# | | | | |# * * * * * command to be executed#-----------------------------------------------------------
使用上面的示例“0 * * * *”,此任务将在每一天的每一个月中的每一天的每一天的每小时的零分钟标记处运行。
Cron 还有一些其他格式,可能会让人感到奇怪,例如使用 Laravel 的 quarterly()
方法生成的表达式
0 0 1 1-12/3 *
每季度运行一次任务意味着它将在 1 月到 12 月的每三个月的第一天的 00:00 运行。奇怪的 1-12/3
语法称为“步长值”,可以与范围结合使用。 crontab – Linux 手册页 将步长值描述如下
步长值可以与范围结合使用。在范围后加“
”指定了在范围内以数字的值为间隔跳过。例如,“0-23/2”可以在小时字段中使用,以指定每隔一个小时执行命令(V7 标准中的替代方法是“0,2,4,6,8,10,12,14,16,18,20,22”)。步长也可以在星号之后使用,因此如果您想说“每两个小时”,只需使用“*/2”。
我建议您阅读手册页,或者至少将其放在手边,以便在您需要更好地了解任务的底层 cron 调度时可以参考。
了解调度事件 API
Laravel 有些很棒的流畅 API,允许您将多个方法调用链接在一起。调度 Event
类也不例外。但是,您可能使用的一些组合存在一些细微差别。
以下示例可以更好地说明:假设我们要让一个命令每小时运行一次,但仅在星期一、星期三和星期五运行
$schedule->command('inspire') ->hourly() ->mondays() ->wednesdays() ->fridays();
您可能认为上面的命令实现了正确的 cron,但事实并非如此。在上面的示例中,最后调用的“day”方法是 fridays()
,因此,cron 如下所示
0 * * * 5
上面的任务将每小时运行一次,但仅在星期五运行。
在我向您展示实现我们想要的功能的正确方法调用之前,让我们先看看 Event::fridays()
方法。fridays()
方法(以及许多其他方法)来自 Laravel 的 ManagesFrequencies 特性
/** * Schedule the event to run only on Fridays. * * @return $this */public function fridays(){ return $this->days(5);}
此方法调用特性上的另一个方法 days()
,该方法在撰写本文时看起来像这样
/** * Set the days of the week the command should run on. * * @param array|mixed $days * @return $this */public function days($days){ $days = is_array($days) ? $days : func_get_args(); return $this->spliceIntoPosition(5, implode(',', $days));}
您可以查看 spliceIntoPosition()
的工作原理,但所有“day”方法都会互相覆盖,因此最后调用的方法会保留。
以下是如何使用 Laravel 的流畅 API 编写正确的调度
$schedule->command('inspire') ->hourly() ->days([1, 3, 5]);
调试此任务实例会产生以下表达式
0 * * * 1,3,5
Bingo!
直接使用 Cron
大多数情况下,我认为大多数人更喜欢使用 Laravel 的流畅 API。但是,Event
任务包括一个 cron()
方法来直接设置表达式
$schedule->command('inspire') ->cron('0 * * * 1,3,5');
我认为 Laravel 的流畅 API 是定义命令更易读的方式,但如果您更喜欢使用 cron 语法,您可以使用此方法获得 cron 的全部功能。
Crontab Guru
对于高级用例以及更好地了解计划任务的运行方式,请考虑调试底层 cron 表达式,并使用诸如 crontab.guru – cron 调度表达式编辑器 之类的工具。