spatie/laravel-cronless-schedule
Run Laravel’s scheduler without cron. This dev/test-friendly package adds php artisan schedule:run-cronless, which uses a ReactPHP loop to execute the scheduler on a timer (default every minute), with optional custom frequency and manual runs.
Installation:
composer require spatie/laravel-cronless-schedule
Publish the config (optional):
php artisan vendor:publish --provider="Spatie\CronlessSchedule\CronlessScheduleServiceProvider"
First Use Case: Run the scheduler locally without cron:
php artisan schedule:run-cronless
Where to Look First:
config/cronless-schedule.php for customization (e.g., interval, logging).app/Console/Kernel.php to define your scheduled tasks (standard Laravel scheduler syntax).Local Development:
cron with php artisan schedule:run-cronless in your package.json scripts or .env:
"scripts": {
"dev": "php artisan schedule:run-cronless & npm run dev"
}
nohup or tmux to keep the process running in the background:
nohup php artisan schedule:run-cronless > cronless.log 2>&1 &
Testing:
Spatie\CronlessSchedule\Testing\CronlessSchedule:
use Spatie\CronlessSchedule\Testing\CronlessSchedule;
public function test_scheduled_job()
{
CronlessSchedule::run();
$this->assertDatabaseHas('jobs', ['status' => 'completed']);
}
php artisan schedule:run-cronless --once # Runs once and exits (for testing)
Integration with CI/CD:
# .github/workflows/test.yml
jobs:
test:
runs-on: ubuntu-latest
steps:
- run: php artisan schedule:run-cronless --once
- run: php artisan test
Custom Intervals:
// config/cronless-schedule.php
'interval' => 30, // Runs every 30 seconds
Logging:
php artisan schedule:run-cronless --verbose
config/cronless-schedule.php:
'log' => [
'enabled' => true,
'channel' => 'single',
],
Environment-Specific Setup:
.env to toggle cronless mode:
CRONLESS_SCHEDULE_ENABLED=true
app/Console/Kernel.php:
protected function schedule(Schedule $schedule)
{
if (env('CRONLESS_SCHEDULE_ENABLED')) {
$schedule->command('schedule:run-cronless')->everyMinute();
}
}
Docker/Containerized Environments:
docker-compose.yml:
services:
app:
command: php artisan schedule:run-cronless
restart: unless-stopped
Blocking the Process:
schedule:run-cronless runs forever by default. Avoid running it in production unless you’re using a process manager (e.g., Supervisor) to manage it.--once for testing or wrap it in a process manager.ReactPHP Dependencies:
Timezone Mismatches:
.env:
APP_TIMEZONE=UTC
Database Locks:
DB_CONNECTION_TIMEOUT.Missing schedule:run Command:
app/Console/Kernel.php, the cronless scheduler will do nothing.$schedule->command('your:command')->everyMinute();
Check Logs:
config/cronless-schedule.php and check storage/logs/laravel.log for errors.Simulate Failures:
CronlessSchedule::run();
$this->expectException(JobFailureException::class);
Inspect ReactPHP Loop:
--verbose to see the loop’s activity:
php artisan schedule:run-cronless --verbose
Custom Commands:
// app/Console/Kernel.php
protected function schedule(Schedule $schedule)
{
$schedule->command('analytics:refresh')->hourly();
$schedule->command('cache:clear')->daily();
}
Event Listeners:
use Spatie\CronlessSchedule\Events\JobExecuted;
Event::listen(JobExecuted::class, function ($event) {
Log::info("Job '{$event->job}' executed at {$event->time}");
});
Custom Interval Logic:
// config/cronless-schedule.php
'interval' => function () {
return env('FAST_SCHEDULE') ? 10 : 60; // 10s or 1m
},
Integration with Laravel Forge/Laravel Vapor:
Default Config:
config/cronless-schedule.php before assuming behavior.Environment Variables:
interval can be set via .env:
CRONLESS_SCHEDULE_INTERVAL=30
Process Management:
[program:scheduler]
command=php /path/to/artisan schedule:run-cronless
autorestart=true
user=www-data
How can I help you explore Laravel packages today?