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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/48684370/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 17:21:50  来源:igfitidea点击:

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

laravellaravel-5artisan

提问by cartbeforehorse

I have a dummy Command job set up, whose handle()function is as follows:

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

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

As you see, it doesn't actually do anything but return a few lines of info to the standard output.

如您所见,它实际上并没有做任何事情,只是将几行信息返回到标准输出。

Now, in my App\Console\Kernelclass, I have set up the following schedule:

现在,在我的App\Console\Kernel课堂上,我制定了以下时间表:

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

Now, from the command-line I run php artisan schedule:run. The output in my laravel_output.logfile reads

现在,我从命令行运行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

So far so good. It seems that my schedule is running. However, if I run the command again within the same minute, my logfile now reads:

到现在为止还挺好。看来我的日程正在运行。但是,如果我在同一分钟内再次运行该命令,我的日志文件现在显示为:

==================
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

In other words, the schedule appears to be running more frequently than every minute, which appears to me to break the rules I defined in my schedule.

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

What's more confusing is that I can change the schedule to run every 5 minutes instead of every minute:

更令人困惑的是,我可以将计划更改为每 5 分钟而不是每分钟运行一次:

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

then run php artisan schedule:run, then I get the following output

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

No scheduled commands are ready to run.

没有准备好运行的预定命令。

I can wait as long as you like (i.e. more than 5 minutes) and still I get no output to my log file.

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

I observe exactly the same behaviour when I schedule my command with Windows Task Scheduler (yes, my development environment is a Windows 7 box, and yes, this is the Windows equivalent of a cron-job).

当我使用 Windows 任务计划程序安排我的命令时,我观察到完全相同的行为(是的,我的开发环境是 Windows 7 机器,是的,这是 Windows 等价的 cron 作业)。

The Question

问题

So what's going on? How does the artisan schedule:runcommand figure out which commands are "waiting" on the schedule to be executed? I had imagined that there would be some kind of log-file to record the fact that "Command X is on a 1-hour schedule and last ran at 09:00, so don't execute it again before 10:00", but I have been able to find no trace of such a log.

发生什么了?artisan schedule:run命令如何确定哪些命令在要执行的计划中“等待”?我曾想象会有某种日志文件来记录这样一个事实:“命令 X 的时间表是 1 小时,最后一次运行是在 09:00,所以不要在 10:00 之前再次执行它”,但是我一直找不到这样的日志的踪迹。

Can someone give me a clue?

有人可以给我一个线索吗?

Thanks!!

谢谢!!

回答by cartbeforehorse

Not cool to answer your own question, I know. Anyhow, let's imagine this is my schedule:

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

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

What I've discovered is that this code doesn't set your job to run every 5 minutes. Nor does it prevent the command running again if it was run less than 5-minutes ago.

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

A better way to think about it is that this code sets the named command "to be runnable every time the minute-figure of the current time is 0or 5". In other words, if I run the command-line argument: php artisan schedule:runat 11:04, then the response is:

更好的思考方式是,这段代码将命名命令设置为“每次当前时间的分位数为0or时都可运行5。换句话说,如果我运行命令行参数:php artisan schedule:runat 11:04,那么响应是:

# No scheduled commands are ready to run.

But if I run the same command at 11:00or 11:05, then we get:

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

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

And I end up with output in my log-file.

我最终在我的日志文件中输出。

I discovered the above when my everyFiveMinutes()schedule was creating a log in my file every 10 minutes based on the fact that my task-scheduler was running every 2 minutes.

everyFiveMinutes()根据我的任务调度程序每 2 分钟运行一次的事实,我在我的日程安排每 10 分钟在我的文件中创建一个日志时发现了上述情况。

回答by Luciano Fantuzzi

I'm answering this just to let other people know it (since I was having the same confusion).

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

Laravel scheduler does exactlythe same job than Linux cron, by checking if a task cronned time (in minutes) is exactly the same of current time.

Laravel 调度器执行与 Linux cron完全相同的工作,通过检查任务的 cronned 时间(以分钟为单位)是否与当前时间完全相同。

When you set in crontab * * * * * ... php artisan schedule:run >> ...you are running schedule:runevery minute at 0 secs, like '1:00:00', '1:01:00', '1:02:00', etc.

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

So, if you set your command to run (let's say) on 'mondays at 1:00' in your Laravel scheduler, and you are on a monday at 1:00, it will be executed, regardless the current seconds. And the last part (seconds) is important to understand how it works.

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

For example, you are on monday at 1:00:05 (5 seconds after 1:00), so cron already launched schedule:runand your task is being executed. Then you open your terminal, go to your project's root directory and launch, manually, php artisan schedule:run. At that time, it may be 1:00:30 (30 seconds after 1:00). Well, now your task will be executed again because 1:00:30 is still part of 1:00. So you can execute N times schedule:runat 1:00 and it will execute N times your task scheduled to run at 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 的一部分。所以你可以schedule:run在 1:00执行 N 次,它会执行 N 次你计划在 1:00 运行的任务

And that's the magic of no needing a table or a file to control process launching time. Minutes is the minimum unit in cron, so unless you are doing the things wrong (like duplicating schedule:runline, a hack to run a command more often than a minute, etc.) your Laravel tasks will be executing once at the desired time.

这就是不需要表或文件来控制进程启动时间的神奇之处。分钟是 cron 中的最小单位,所以除非你做错了事情(比如复制schedule:run行,黑客以超过一分钟的频率运行命令等)你的 Laravel 任务将在所需的时间执行一次。

Just a note: Check that your timezone is correct in config/app.php. I got crazy to understand why things like everyMinute(), everyFiveMinutes()were working, and dailyAt('1:10')were not. Of course, with Laravel in UTC and me being in GMT-3 (server clock), I had a great difference in hours.

请注意:检查您的时区在config/app.php. 我很疯狂地理解为什么像这样的事情everyMinute(), everyFiveMinutes()有效,而dailyAt('1:10')没有。当然,由于 Laravel 在 UTC 而我在 GMT-3(服务器时钟),我在小时数上有很大的不同。