How can i use scheduler in seconds manner in Laravel 5.#

巧了我就是萌 提交于 2020-01-14 19:10:19

问题


there i am trying to schedule some task in larave, but i find it hard to schedule my task in every 20 seconds. Checking laravel doc. for laravel schedular, it didn't have such method for seconds. While there is ->cron('* * * * * *') "Run the task on a custom Cron schedule", but it also couldn't solve my problem.

Below is my code in kernal.php file for scheduling.

protected function schedule(Schedule $schedule)
{ 
    // need to replace everyMinute() by some other method which can run it every 20 sec

    $schedule->call('path\to\controller@method)->everyMinute();

   // also tried cron() but didn't workout.
    $schedule->call('path\to\controller@method)->cron(*/20 * * * * *);
}    

Thanks.


回答1:


There's no method that will do this for you out of the box, however there are a few suggestions of people who have been in the same situation as you already.

->cron(*/20 * * * * *) is actually saying run this every 20 minutes, not every 20 seconds. Given that cron doesn't go down to a sub-minute resolution this is probably why Laravel doesn't support it either.

If this really needs to run more than every 30 seconds then I would go for a combination of the two here: Laravel 5 schedule job every 30 seconds and Laravel schedular: execute a command every second

That is to say, you should still call your command every minute, but add the withoutOverlapping() method just to be safe.

Then inside your command you can run your code, sleep for 20 seconds, run it again, sleep for 20 seconds, and then run it again. This obviously works on the premise that your code is almost instantaneous to run. For example, if your code takes 5 seconds to run and then you sleep for 20 seconds and then run it again - your code is actually running every 25 seconds.

I imagine you have a fairly good idea of how long this code takes to run. If not, time it manually whilst running the artisan command to get an idea - something like this might help date && php artisan your:command && date. This will output the date in your shell, run the command then output the date again - this includes the time which you can use to see how many seconds it takes to run.

This will require you to either refactor the controller action out to a command or add the sleep() code to your controller action. The docs for artisan commands should help here.

I would suggest refactoring this into a command, but it's up to you.

//Console command
public function handle()
{
    \App\Investment::calculate(); //takes 2 seconds to run
    sleep(18); //sleep for 18 seconds to ensure we are only running the command every 20 seconds
    \App\Investment::calculate(); //takes 2 seconds to run
    sleep(18);
    \App\Investment::calculate(); //takes 2 seconds to run
}


//The console scheduler - Kernel.php  
protected function schedule(Schedule $schedule)
{     
    $schedule->call('path\to\controller@method)->everyMinute()->withoutOverlapping();
}   



回答2:


The thing is we can't handle scheduler on seconds basis but we can customize the closer of schedule() method by calling our method number of times based on how much time it takes to execute e.g:

    $obj = new ClassName();

    $schedule->call(function () use ($obj) {

            sleep(3);
        //call method calculate time it takes and based on that we can call method number of methods we want 
            $obj->method(); //call method
            sleep(3);       // pause of 3 seconds
            $obj->method(); //call again
            sleep(3);
            $obj->method(); //call again
            sleep(3);

    })->everyMinute();

Here i was able to call my method three times in one minute based on how time it takes to execute. Thanks i got my work done.




回答3:


I would advise a different approach vs. having delays in your PHP task handler code, for a variety of reasons. For one thing you are mixing different kinds of logic in your handler function (timing should be handled by the scheduler and not inside your task's code). Also if your calls in between the delays take a substantial amount of time your overall timing will get distorted (by itself this could be overcome of course by measuring call duration and taking that into account with the next delay). But there could also be some exception in the first call causing the subsequent calls to not even be reached. Etc.

A more common approach with cron for this is by simply adding multiple cron jobs and imposing an increasing delay on each of them. So:

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

This way you are sure that schedule will run exactly once every 20 seconds. Also you can easily adjust the frequency without having to change your PHP code.

edit: in addition and for completeness; in combination with the above you must schedule your tasks using:

->cron('* * * * *')

This works because with a schedule like this the task is always invoked when the scheduler runs. As the scheduler expects to be run at most once a minute. Backtrace to verify:

Event::expressionPasses (\illuminate\console\Scheduling\Event.php:296)  
CronExpression::isDue (\dragonmantank\cron-expression\src\Cron\CronExpression.php:284)  
CronExpression::getNextRunDate (\dragonmantank\cron-expression\src\Cron\CronExpression.php:195)  
CronExpression::getRunDate (\dragonmantank\cron-expression\src\Cron\CronExpression.php:322)  


来源:https://stackoverflow.com/questions/46701362/how-can-i-use-scheduler-in-seconds-manner-in-laravel-5

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