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 调度器:每秒执行一个命令的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 8 任务调度器

Laravel 计划任务(任务调度)的使用

Laravel 计划任务(任务调度)的使用

laravel 动态添加调度器

mysql 定时任务的使用

laravel 任务调度器