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

两盒软妹~` 提交于 2021-01-02 05:30:29

问题


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

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\Kernel class, I have set up the following schedule:

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.log file reads

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

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

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.

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).

The Question

So what's going on? How does the artisan schedule:run command 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.

Can someone give me a clue?

Thanks!!


回答1:


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.

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 0 or 5". In other words, if I run the command-line argument: php artisan schedule:run at 11:04, then the response is:

# No scheduled commands are ready to run.

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

# 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.




回答2:


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

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

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

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.

For example, you are on monday at 1:00:05 (5 seconds after 1:00), so cron already launched schedule:run and 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:run at 1:00 and it will execute N times your task scheduled to run at 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:run line, a hack to run a command more often than a minute, etc.) your Laravel tasks will be executing once at the desired time.

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.



来源:https://stackoverflow.com/questions/48684370/laravel-artisan-how-does-schedulerun-work

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!