A package to run the Laravel scheduler without relying on cron
We released a new package called spatie/laravel-cronless-schedule. It can run the Laravel scheduler (or any other command really), without relying on cron. Instead of cron, a never-ending ReactPHP loop is used.
In this blog post, I'd like to introduce the package to you.
Why not rely on cron?
Laravel's native scheduler relies on cron to be executed every minute. It's rock solid. If you use *nix machines to run your production environment, you should stick to using it.
In one of my projects, I'd like to test the behavior of one of the scheduled commands. Sure, I could manually fire off the command, but in this case, I wanted to see what the effects where if the command were to be fired on time for an extended period.
If you want to run the scheduler every minute in a local environment, using cron can be cumbersome. I bet most developers will never have touched their local crontab. There's also launchd
, which can work great, but it's not as easy as just running the artisan command that spatie/laravel-cronless-schedule provides.
On Windows, cron doesn't even exist (I'm not an expert, but there you should use the Windows Scheduler). And on Docker containers, cron mostly isn't available.
Using the package
This is how you can start the cronless schedule:
php artisan schedule:run-cronless
This command will never end. Behind the scenes, it will execute php artisan schedule:run
every minute.
To perform an extra run of the scheduler, you can just press enter.
If you want to run the scheduler at another frequency, you can pass a number of seconds to the frequency
option. Here is an example where the schedule will be run every 5 seconds.
php artisan schedule:run-cronless --frequency=5
By default, the command will run forever. You can shorten that period by passing a number of seconds to the stop-after-seconds
option.
In this example, we'll stop the command after 120 seconds
php artisan cronless-schedule:run --stop-after-seconds=120
If you want to run another command instead of the scheduler, you can pass it to the command
option. Here is an example where another command will be run.
php artisan cronless-schedule:run --command=your-favorite-artisan-command
How it works behind the scenes
The package is quite simple. The ScheduleRunCronlessCommand
class that contains all functionality is less than 100 lines long.
The heart of the command consists of these two functions.
protected function scheduleCommand(): self
{
$stopAfter = (int)$this->option('stop-after-seconds');
if ($stopAfter > 0) {
$this->loop->addTimer($stopAfter, fn () => $this->loop->stop());
}
$this->loop->addPeriodicTimer($this->frequency, fn () => $this->runCronlessCommand());
return $this;
}
protected function runCronlessCommand()
{
$this->comment($this->timestamp("Running {$this->command}..."));
$this->call($this->command);
$this->comment($this->timestamp("{$this->command} finished."));
$this->comment('');
}
$this->loop
contains a ReactPHP powered loop. The addPeriodicTimer
accepts two parameters. The first one is a number of seconds. The second one is a callable. If you pass 60 to as the first argument, then the callable will be run every 60 seconds. And that is basically all there is to it.
You might wonder if ReactPHP is reliable enough for this task. Well, the library has been downloaded for millions of times already, and in my experience, it is rock solid.
If you want to see another use of a ReactPHP loop, that check out [this video], in which I explain how ReactPHP powers another cron related package of ours: spatie/laravel-short-schedule.
In closing
For my local testing needs spatie/laravel-cronless-schedule works great, and I hope this package comes in handy for you as well.
Be sure to check out this list of packages that our team has created previously.
Well explained! its helps me allot. I have also read another blog to use Cron jobs with Laravel might be that would help someone’s query regarding Laravel hosting for cron job.