2.6 KiB
Task scheduling best practices
Prevent unwanted overlap
Use withoutOverlapping() when a second run must not begin while the previous run holds the lock. Use it for variable-duration tasks that are not safe to run concurrently.
Schedule::command('reports:generate')
->everyFifteenMinutes()
->withoutOverlapping(30);
The optional value is the lock expiration time in minutes, not the task timeout. Choose the value carefully. The default is 24 hours, and an expiration that is too short can permit overlap while the first task still runs. Clear stale locks with php artisan schedule:clear-cache. The task itself should still tolerate retries and partial execution where practical.
Run a task on one server
Use onOneServer() when only one scheduler node should run an eligible task. Scheduler nodes must use the same default cache store, and that store must support atomic locks. Supported stores include database, memcached, dynamodb, and redis.
Schedule::command('billing:charge')->daily()->onOneServer();
Name scheduled closures before applying onOneServer(), especially when scheduling the same closure with different parameters, so each task has a distinct lock identity.
Run eligible commands in the background
Tasks due at the same time run sequentially by default. Use runInBackground() when an independent, long-running scheduled command should not delay later tasks.
Schedule::command('analytics:process')->hourly()->runInBackground();
Laravel restricts runInBackground() to tasks scheduled with command() and exec(). It is not available for scheduled closures. Give background processes logging and failure monitoring.
Restrict tasks by environment
Use environments() when a task should run only in named application environments. Treat environments() as an operational safeguard, not an authorization control.
Schedule::command('billing:charge')
->monthly()
->environments(['production']);
Group shared configuration
Use schedule groups when several tasks share frequency or constraints.
Schedule::daily()
->onOneServer()
->timezone('America/New_York')
->group(function () {
Schedule::command('emails:send --force');
Schedule::command('emails:prune');
});
Bound work inside the task
The scheduler does not provide a takeUntilTimeout() event method or terminate arbitrary tasks at a deadline. Bound work in the command or job itself by processing finite chunks, checking a deadline, or dispatching queue jobs with suitable timeouts. Use operating-system or process controls when hard termination is required.