Laravel Artisan:`schedule:运行` 是如何工作的?

Laravel Artisan: How does `schedule:run` work?

我设置了一个虚拟命令作业,其handle()功能如下:

public function handle()
{
    $this->line('==================');
    $this->line('Running my job at ' . Carbon::now());
    $this->line('Ending my job at ' . Carbon::now());
}

如您所见,除了 return 标准输出的几行信息外,它实际上什么也没做。

现在,在我的 App\Console\Kernel class 中,我设置了以下时间表:

protected function schedule(Schedule $schedule)
{
    $schedule
        -> command('cbh:dummyCommand')
        -> everyMinute()
        -> appendOutputTo (storage_path().'/logs/laravel_output.log');
}

现在,从command-line我运行php artisan schedule:run。我的 laravel_output.log 文件中的输出显示为

==================
Running my job at 2018-02-08 11:01:33
Ending my job at 2018-02-08 11:01:33

到目前为止一切顺利。看来我的日程是运行ning。但是,如果我在同一分钟内再次 运行 命令,我的日志文件现在显示为:

==================
Running my job at 2018-02-08 11:01:33
Ending my job at 2018-02-08 11:01:33
==================
Running my job at 2018-02-08 11:01:51
Ending my job at 2018-02-08 11:01:51

换句话说,时间表似乎比每分钟都更 运行ning,这在我看来违反了我在时间表中定义的规则。

更令人困惑的是,我可以将时间表更改为每 5 分钟而不是每分钟 运行:

protected function schedule(Schedule $schedule)
{
    $schedule
        -> command('cbh:dummyCommand')
        -> everyFiveMinutes()
        -> appendOutputTo (storage_path().'/logs/laravel_output.log');
}

然后运行php artisan schedule:run,然后我得到以下输出

No scheduled commands are ready to run.

我可以等多久(即超过 5 分钟),但我的日志文件仍然没有输出。

当我使用 Windows Task Scheduler 安排我的命令时,我观察到完全相同的行为(是的,我的开发环境是一个 Windows 7 框,是的,这是 Windows 相当于 cron-job).

问题

所以这是怎么回事? artisan schedule:run 命令如何确定要执行的计划中 "waiting" 哪些命令?本来以为会有什么log-file来记录"Command X is on a 1-hour schedule and last ran at 09:00, so don't execute it again before 10:00",但是一直找不到这样的日志的踪迹。

有人可以给我线索吗?

谢谢!!

我知道回答你自己的问题不太酷。无论如何,让我们想象这是我的日程安排:

protected function schedule(Schedule $schedule)
{
    $schedule
        -> command('cbh:dummyCommand')
        -> everyFiveMinutes()
        -> appendOutputTo ('/my/logs/laravel_output.log');
}

我发现此代码不会将您的作业设置为每 5 分钟 运行。如果 运行 不到 5 分钟前,它也不会再次阻止命令 运行ning。

更好的思考方式是这段代码设置命名命令"to be runnable every time the minute-figure of the current time is 0 or 5"。换句话说,如果我 运行 命令行参数:php artisan schedule:run at 11:04,那么响应是:

# No scheduled commands are ready to run.

但是如果我 运行 在 11:0011:05 处执行相同的命令,那么我们会得到:

# Running scheduled command: php artisan cbh:dummyCommand >> /my/logs/laravel_output.log 2>&1

最后我的日志文件中有输出。

当我的 everyFiveMinutes() 计划每 10 分钟在我的文件中创建一个日志时,我发现了上述情况,因为我的任务计划程序每 2 分钟 运行ning 一次。

我回答这个问题只是为了让其他人知道(因为我也有同样的困惑)。

Laravel 调度程序 与 Linux cron 完成 相同的工作,通过检查任务的 cronned 时间(分钟) 与当前时间完全一致

当您在 crontab * * * * * ... php artisan schedule:run >> ... 中设置时,您每分钟 0 秒 运行ning schedule:run,例如'1:00:00'、'1:01:00'、'1:02:00'等

因此,如果您在 Laravel 调度程序中将命令设置为 运行(比方说)'mondays at 1:00',并且您是在周一的 1:00,它将被执行,不管当前秒数。最后一部分()对于理解它是如何工作的很重要。

例如,您在星期一 1:00:05(1:00 后 5 秒),因此 cron 已经启动 schedule:run 并且您的任务正在执行。然后打开终端,转到项目的根目录并手动启动 php artisan schedule:run。那时,可能是1:00:30(1:00后30秒)。那么,现在您的任务将再次执行,因为 1:00:30 仍然是 1:00 的一部分。所以你可以在1:00执行N次schedule:run,它会在1:00执行N次你计划运行的任务。

这就是不需要 table 或文件来控制进程启动时间的神奇之处。分钟是 cron 中的最小单位,所以除非你做错了事(比如复制 schedule:run 行,破解 运行 命令 more often than a minute 等)你的 Laravel 任务将在所需时间执行一次。

请注意:请检查您在 config/app.php 中的时区是否正确。我疯狂地理解为什么像 everyMinute(), everyFiveMinutes() 这样的东西有效,而 dailyAt('1:10') 却没有。当然,UTC 的 Laravel 而我的 GMT-3(服务器时钟),我的小时数有很大差异。