如何在 Laravel 5 中以秒的方式使用调度程序#

问题描述 投票:0回答:7

我正在尝试在 Larave 中安排一些任务,但我发现很难每 20 秒安排一次任务。检查 Laravel 文档。对于 laravel schedular,它已经几秒钟没有这样的方法了。虽然有 ->cron('* * * * * *') “按照自定义 Cron 计划运行任务”,但它也无法解决我的问题。

下面是我在 kernal.php 文件中用于调度的代码。

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 * * * * *);
}    

谢谢。

laravel cron scheduler
7个回答
13
投票

没有任何方法可以立即为您执行此操作,但是已经与您处于相同情况的人提供了一些建议。

->cron(*/20 * * * * *)
实际上是说每 20 分钟运行一次,而不是每 20 秒运行一次。鉴于 cron 不会达到亚分钟的分辨率,这可能就是 Laravel 也不支持它的原因。

如果这确实需要每 30 秒运行一次以上,那么我会在这里结合使用两者:Laravel 5 每 30 秒调度作业Laravel 调度:每秒执行一个命令

也就是说,你仍然应该每分钟调用你的命令,但为了安全起见添加

withoutOverlapping()
方法。

然后在命令中,您可以运行代码,休眠 20 秒,再次运行,休眠 20 秒,然后再次运行。显然,这在您的代码几乎可以立即运行的前提下有效。 例如,如果您的代码需要 5 秒才能运行,然后您休眠 20 秒,然后再次运行它 - 您的代码实际上每 25 秒运行一次。

我想您非常清楚这段代码的运行时间。如果没有,请在运行 artisan 命令时手动计时以获得想法 - 这样的事情可能会有所帮助

date && php artisan your:command && date
。 这将在您的 shell 中输出日期,运行命令,然后再次输出日期 - 这包括您可以用来查看运行需要多少秒的时间。

这将要求您将控制器操作重构为命令或将

sleep()
代码添加到控制器操作中。 artisan 命令的 docs 应该会有所帮助。

我建议将其重构为命令,但这取决于你。

//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();
}   

5
投票

最近,Spatie 发布了一个软件包,使您能够以亚分钟的间隔安排命令。你可以做一些很酷的事情,比如:

protected function shortSchedule(\Spatie\ShortSchedule\ShortSchedule $shortSchedule)
{
    // this command will run every second
    $shortSchedule->command('artisan-command')->everySecond();

    // this command will run every 30 seconds
    $shortSchedule->command('another-artisan-command')->everySeconds(30);

    // this command will run every half a second
    $shortSchedule->command('another-artisan-command')->everySeconds(0.5);
}  

参见 spatie/laravel-short-schedule


4
投票

问题是我们无法以秒为单位处理调度程序,但我们可以根据执行所需的时间来调用我们的方法次数来自定义schedule()方法的结束时间,例如:

    $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();

在这里,我能够根据执行所需的时间在一分钟内调用我的方法三次。 谢谢我完成了我的工作。


3
投票

出于各种原因,我建议采用不同的方法,而不是在 PHP 任务处理程序代码中出现延迟。一方面,您在处理程序函数中混合了不同类型的逻辑(计时应由调度程序处理,而不是在任务代码内处理)。此外,如果您在延迟之间的呼叫花费了大量时间,那么您的整体计时将会失真(当然,这可以通过测量呼叫持续时间并将其与下一个延迟考虑在内来克服)。但第一次调用中也可能出现一些异常,导致后续调用甚至无法到达。等等

更常见的 cron 方法是简单地添加多个 cron 作业并对每个作业施加越来越大的延迟。所以:

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

这样您就可以确保计划每 20 秒运行一次。 您还可以轻松调整频率,而无需更改 PHP 代码。

编辑:补充和完整性;结合上述内容,您必须使用以下方式安排您的任务:

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

这是可行的,因为使用这样的计划,任务总是在计划程序运行时被调用。由于调度程序预计最多每分钟运行一次。回溯验证:

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)  

0
投票

在 Laravel 5.7 :-) 绝对工作正常。

添加

app/Console/Kernel.php

$seconds = 5;
$schedule->call(function () use ($seconds) {
    $dt = Carbon::now();
    $x = 60 / $seconds;
    do {
        // do your function here that takes between 3 and 4 seconds
        \Log::debug($x . ' executing at ' . date('Y-m-d H:i:s'));
        time_sleep_until($dt->addSeconds($seconds)->timestamp);
    } while ($x-- > 1);
})->everyMinute();

0
投票

这对我有用

    $function = function(){
        // Your codes
    };

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

        $time = time();
        $function();
        sleep(30 - (time() - $time));
        $function();

    })->everyMinute();

0
投票

您可以使用 while 循环来运行,因为这将继续运行

protected function schedule(Schedule $schedule)
{
        while (true) {
            Artisan::call('Command Goes Here');
            sleep(2);
        }
        $schedule->command('other command')->daily();

}
    ```
© www.soinside.com 2019 - 2024. All rights reserved.