我如何在 Laravel 5.# 中以秒的方式使用调度程序
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/46701362/
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
How can i use scheduler in seconds manner in Laravel 5.#
提问by shakir
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.
我正在尝试在 laave 中安排一些任务,但我发现很难每 20 秒安排一次我的任务。检查 Laravel 文档。对于laravel schedular,它几秒钟没有这样的方法。虽然有 ->cron('* * * * * *') “按自定义 Cron 计划运行任务”,但它也无法解决我的问题。
Below is my code in kernal.php file for scheduling.
下面是我在 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 * * * * *);
}
Thanks.
谢谢。
回答by James
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.
->cron(*/20 * * * * *)
实际上是说每 20 分钟运行一次,而不是每 20 秒运行一次。鉴于 cron 没有达到亚分钟级的分辨率,这可能就是 Laravel 也不支持它的原因。
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 secondsand Laravel schedular: execute a command every second
如果这真的需要每 30 秒运行一次以上,那么我会在这里结合两者:Laravel 5 schedule job every 30 seconds和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.
也就是说,你仍然应该每分钟调用你的命令,但withoutOverlapping()
为了安全起见添加方法。
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.
然后在你的命令中你可以运行你的代码,休眠 20 秒,再次运行,休眠 20 秒,然后再次运行它。这显然是在您的代码几乎可以立即运行的前提下起作用的。例如,如果您的代码运行需要 5 秒,然后您休眠 20 秒,然后再次运行它 - 您的代码实际上每 25 秒运行一次。
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.
我想您很清楚这段代码需要多长时间才能运行。如果没有,请在运行 artisan 命令的同时手动计时以获得一个想法 - 这样的事情可能会有所帮助date && php artisan your:command && date
。这将在您的 shell 中输出日期,运行命令然后再次输出日期 - 这包括您可以用来查看运行所需的秒数的时间。
This will require you to either refactor the controller action out to a command or add the sleep()
code to your controller action. The docsfor artisan commands should help here.
这将要求您将控制器操作重构为命令或将sleep()
代码添加到您的控制器操作中。工匠命令的文档应该在这里有所帮助。
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();
}
回答by shakir
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:
问题是我们不能以秒为单位处理调度程序,但我们可以根据执行所需的时间调用我们的方法次数来自定义 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();
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.
在这里,根据执行所需的时间,我能够在一分钟内调用我的方法三次。谢谢我完成了我的工作。
回答by Arthur
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.
出于各种原因,我建议采用不同的方法,而不是在 PHP 任务处理程序代码中出现延迟。一方面,您在处理程序函数中混合了不同类型的逻辑(计时应该由调度程序处理,而不是在您的任务代码中)。此外,如果您在延迟之间的通话花费了大量时间,您的整体时间将被扭曲(当然,这可以通过测量通话持续时间并将其与下一次延迟考虑在内来克服)。但是在第一次调用中也可能存在一些异常,导致后续调用甚至无法到达。等等。
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:
对此使用 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
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.
通过这种方式,您可以确保计划每 20 秒恰好运行一次。您还可以轻松调整频率,而无需更改 PHP 代码。
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)