Laravel Task Scheduling & Cron: Step-by-Step Guide

·

·

Laravel scheduler transforms one cron entry into a rich timetable of commands, closures, and queued jobs with overlap protection, environments, and maintenance mode awareness.

Defining Scheduled Tasks

Schedule definitions live in routes/console.php in Laravel 11 or app/Console/Kernel.php in older versions.

The Schedule facade accepts commands, invokable classes, jobs, and shell callbacks.

Step 1: Register a basic command schedule

Add Schedule::command('reports:daily')->dailyAt('08:00'); in routes/console.php.

List schedules with php artisan schedule:list showing next run times and cron expressions.

Schedule::command('reports:daily')->dailyAt('08:00');

Step 2: Create the Artisan command

Run php artisan make:command SendDailyReport and implement handle() with business logic or dispatch a job.

Keep commands thin—delegate heavy work to queued jobs for retry support.

php artisan make:command SendDailyReport

Step 3: Schedule closures and invokable classes

Schedule::call(fn () => CleanupService::run())->hourly() works for small tasks.

Invokable classes improve testability: Schedule::call(new PruneTempFiles)->daily().

Schedule::call(new PruneTempFiles)->daily();

Step 4: Queue scheduled tasks

Chain ->job(new GenerateReport)->daily() to push work to the queue instead of running inline.

Queued schedules need workers running. Inline schedules need the scheduler process itself.

Schedule::job(new GenerateReport)->dailyAt('06:00');

Cron Expressions and Constraints

Laravel fluent methods like hourly(), weeklyOn(), and cron() map to cron syntax.

Constraints prevent tasks from running during deployments or outside business hours.

Step 1: Use fluent scheduling methods

Examples: ->everyMinute(), ->twiceDaily(1, 13), ->weekdays(), ->monthlyOn(1, '00:00').

Prefer fluent methods over raw cron strings for readability unless you need exotic timing.

Schedule::command('sync:inventory')->everyFiveMinutes()->between('8:00', '20:00');

Step 2: Prevent overlapping runs

Chain ->withoutOverlapping() so a slow run does not stack duplicates. Optional ->runInBackground() for shell commands.

Mutex uses cache by default. Ensure cache driver supports atomic locks in production.

Schedule::command('imports:run')->hourly()->withoutOverlapping();

Step 3: Limit to environments

Use ->environments(['production']) so staging does not send live emails or charge customers.

Combine with ->when(fn () => config('features.reports')) for feature-flagged schedules.

Schedule::command('billing:charge')->daily()->environments(['production']);

Step 4: Maintenance mode behavior

Tasks skip automatically during php artisan down unless ->evenInMaintenanceMode() is set.

Critical health checks may use evenInMaintenanceMode while batch emails should pause.

Schedule::command('health:ping')->everyMinute()->evenInMaintenanceMode();

Server Cron and Monitoring

Production servers need exactly one cron entry calling schedule:run every minute.

Log output and alert on failures to catch silent scheduler breakage.

Step 1: Add crontab entry

Run crontab -e and add * * * * * cd /var/www/app && php artisan schedule:run >> /dev/null 2>&1.

Use absolute paths and the deploy user. Wrong paths are the most common scheduler failure.

* * * * * cd /var/www/myapp && php artisan schedule:run >> /dev/null 2>&1

Step 2: Test with schedule:run locally

php artisan schedule:run executes due tasks immediately. Use schedule:test for interactive debugging in Laravel 11.

Temporarily set ->everyMinute() during development to verify wiring.

php artisan schedule:run
php artisan schedule:test

Step 3: Log output to files

Chain ->sendOutputTo(storage_path('logs/backup.log')) or appendOutputTo for audit trails.

Email output sparingly with emailOutputTo—prefer centralized logging.

->appendOutputTo(storage_path('logs/daily-report.log'));

Step 4: Monitor with Laravel Pulse or external tools

Track scheduler heartbeat externally. If schedule:run stops, alerts fire before missed backups become incidents.

Document every scheduled task in your ops runbook with owner and expected duration.

  • Heartbeat monitoring
  • Runbook per scheduled task

Aadyanex builds production-ready Laravel applications with clean architecture, secure APIs, and long-term support.