Laravel schedular: execute a command every second

14,679

Solution 1

Usually, when you want more granularity than 1 minute, you have to write a daemon.

I advise you to try, now it's not so hard as it was some years ago. Just start with a simple loop inside a CLI command:

while (true) {
    doPeriodicStuff();

    sleep(1);
}

One important thing: run the daemon via supervisord. You can take a look at articles about Laravel's queue listener setup, it uses the same approach (a daemon + supervisord). A config section can look like this:

[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

Solution 2

for per second you can add command to cron job

*   *   *   *   *   /usr/local/php56/bin/php56 /home/hamshahr/domains/hamshahrapp.com/project/artisan taxis:beFreeTaxis 1>> /dev/null 2>&1

and in command :

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

    }
}

Solution 3

$schedule->call(function(){
    while (some-condition) {
        runProcess();
    }
})->name("someName")->withoutOverlapping();

Depending on how long your runProcess() takes to execute, you can use sleep(seconds) to have more fine tuning.

some-condition is normally a flag that you can change any time to have control on the infinite loop. e.g. you can use file_exists(path-to-flag-file) to manually start or stop the process any time you need.

Share:
14,679

Related videos on Youtube

Naveed
Author by

Naveed

Learning web applications development for more than five years...

Updated on September 18, 2022

Comments

  • Naveed
    Naveed about 1 year

    I have a project that needs to send notifications via WebSockets continuously. It should connect to a device that returns the overall status in string format. The system processes it and then sends notifications based on various conditions.

    Since the scheduler can repeat a task as early as a minute, I need to find a way to execute the function every second.

    Here is my 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: If you have a better idea to handle the situation, please share your thoughts.

    • Mjh
      Mjh over 7 years
      A daemon using an event loop which triggers every second. You can use a library such as icicle for this task and supervisord as the manager which will boot up the process if it exits unexpectedly. This might seem as an overkill, but certain things do look simple until you get to the core of the problem. If you need continuous updates, this is the way to go.
  • Binar Web
    Binar Web over 2 years
    Note: you might want to implement this command with a locking mechanism and retries, because if the last task is taking a few seconds to complete (in the minute interval), it will overlap with the new minute first task.