Laravel 调度器:每秒执行一个命令
Posted
技术标签:
【中文标题】Laravel 调度器:每秒执行一个命令【英文标题】:Laravel schedular: execute a command every second 【发布时间】:2016-11-29 21:39:08 【问题描述】:我有一个项目需要通过 WebSockets 连续发送通知。它应该连接到以字符串格式返回整体状态的设备。系统对其进行处理,然后根据各种情况发送通知。
由于调度器最早可以在一分钟内重复一个任务,所以我需要找到一种方法来每秒执行一次函数。
这是我的app/Console/Kernel.php
:
<?php
...
class Kernel extends ConsoleKernel
...
protected function schedule(Schedule $schedule)
$schedule->call(function()
// connect to the device and process its response
)->everyMinute();
PS:如果你有更好的想法来处理这种情况,请分享你的想法。
【问题讨论】:
一个使用每秒触发的事件循环的守护进程。您可以使用诸如icicle 之类的库来执行此任务,并使用supervisord 作为管理器,如果进程意外退出,它将启动进程。这可能看起来有点矫枉过正,但在你找到问题的核心之前,某些事情看起来确实很简单。如果您需要持续更新,这就是您要走的路。 【参考方案1】:这可能是一个有点老的问题,但我建议你看看
laravel-short-schedule 来自 spatie 的包
它允许您在亚分钟甚至亚秒内运行命令
【讨论】:
【参考方案2】:每秒你可以将命令添加到 cron 作业中
* * * * * /usr/local/php56/bin/php56 /home/hamshahr/domains/hamshahrapp.com/project/artisan taxis:beFreeTaxis 1>> /dev/null 2>&1
并在命令中:
<?php
namespace App\Console\Commands;
use App\Contracts\Repositories\TaxiRepository;
use App\Contracts\Repositories\TravelRepository;
use App\Contracts\Repositories\TravelsRequestsDriversRepository;
use Carbon\Carbon;
use Illuminate\Console\Command;
class beFreeRequest extends Command
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'taxis:beFreeRequest';
/**
* The console command description.
*
* @var string
*/
protected $description = 'change is active to 0 after 1 min if yet is 1';
/**
* @var TravelsRequestsDriversRepository
*/
private $travelsRequestsDriversRepository;
/**
* Create a new command instance.
* @param TravelsRequestsDriversRepository $travelsRequestsDriversRepository
*/
public function __construct(
TravelsRequestsDriversRepository $travelsRequestsDriversRepository
)
parent::__construct();
$this->travelsRequestsDriversRepository = $travelsRequestsDriversRepository;
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
$count = 0;
while ($count < 59)
$startTime = Carbon::now();
$this->travelsRequestsDriversRepository->beFreeRequestAfterTime();
$endTime = Carbon::now();
$totalDuration = $endTime->diffInSeconds($startTime);
if($totalDuration > 0)
$count += $totalDuration;
else
$count++;
sleep(1);
【讨论】:
注意:您可能希望使用锁定机制实现此命令并重试,因为如果最后一个任务需要几秒钟才能完成(在分钟间隔内),它将与新的分钟重叠第一个任务。【参考方案3】:$schedule->call(function()
while (some-condition)
runProcess();
)->name("someName")->withoutOverlapping();
根据您的runProcess()
执行时间长短,您可以使用sleep(seconds)
进行更多微调。
some-condition
通常是一个标志,您可以随时更改它以控制无限循环。例如您可以随时使用file_exists(path-to-flag-file)
手动启动或停止进程。
【讨论】:
【参考方案4】:通常,当您想要超过 1 分钟的粒度时,您必须编写一个守护进程。
我建议你尝试一下,现在它不像几年前那么难了。只需从 CLI 命令中的一个简单循环开始:
while (true)
doPeriodicStuff();
sleep(1);
一件重要的事情:通过supervisord 运行守护程序。您可以查看有关 Laravel 的队列侦听器设置的文章,它使用相同的方法(守护进程 + supervisord)。配置部分可能如下所示:
[program:your_daemon]
command=php artisan your:command --env=your_environment
directory=/path/to/laravel
stdout_logfile=/path/to/laravel/app/storage/logs/your_command.log
redirect_stderr=true
autostart=true
autorestart=true
【讨论】:
您介意澄清一下为什么应该运行 supervisord 吗? supervisord 需要在脚本失败时自动重新启动脚本,将 STDOUT 和 STDERR 输出记录到日志文件中,以及执行您不想添加到 PHP 代码中的其他基础设施事情。跨度> 顺便说一句,不需要supervisord,你也可以使用systemctl来达到同样的目的。 laravel 使用 supervisord 的原因是因为它更擅长同时生成队列所需的多个进程,但对于这种情况,它没有任何好处。【参考方案5】:您可以尝试使用 sleep(1) 每秒复制作业 * 60 次。
【讨论】:
以上是关于Laravel 调度器:每秒执行一个命令的主要内容,如果未能解决你的问题,请参考以下文章