The Laravel 13 scheduler lets you define scheduled tasks in PHP and run them with a single cron entry, instead of maintaining many cron lines. You add one cron line that calls the scheduler every minute, and Laravel decides which tasks are due and executes them. This article walks through the full path from that cron entry to the actual execution of your scheduled events, including how the scheduler avoids overlap, handles timezones, and runs tasks in the background.
Formula
The scheduler itself doesn’t use a math formula, but the cron entry is the trigger. The formula for the cron line is:
* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
That line runs every minute. The variables are the five cron time fields (minute, hour, day of month, month, day of week) and the path to your Laravel project. The scheduler then evaluates each registered event to see if it is due.
Worked Example
Suppose you have a scheduled command that runs daily at 1:00 AM:
Schedule::command('reports:generate')->dailyAt('01:00');
At 1:00:00, the cron entry fires schedule:run. The scheduler checks all events: the current time matches the event’s expression, so it marks the event as due. It then runs the command via the console kernel. If the command takes 2 minutes, it finishes at 1:02. The next cron fire at 1:01 does not run it again because the event is not due again until the next day.
Background and Purpose
Before the scheduler, developers added a separate cron line for each task. With a dozen tasks, you had a dozen cron lines, each with its own path and PHP binary. Laravel’s scheduler consolidates all that into one line and gives you a fluent API to define when tasks run. It also adds features that plain cron lacks: overlapping prevention, task output handling, notifications on failure, and easy testing.
The scheduler was introduced in Laravel 5.0 and has been refined since. In Laravel 13, the core mechanism remains the same, but the API has grown to include more expressive methods like everyOddHour(), onOneServer(), and withoutOverlapping().
How the Scheduler Works Step by Step
Here is the exact flow from cron to execution:
- Cron fires – The system cron daemon runs
php artisan schedule:runevery minute. - Bootstrap – The Artisan command boots the Laravel application, loading the service providers and registering all scheduled events (usually in
App\Console\Kernelor via theSchedulefacade). - Due evaluation – The scheduler iterates over all registered events and checks if the current time matches the event’s cron expression. It also checks timezone, environment, and any custom conditions (e.g.,
when()closures). - Filtering – Events that are not due are skipped. Events that are due but have overlapping prevention enabled are checked against a lock file; if another instance is still running, they are skipped.
- Execution – Due events are run. By default, they run in the foreground, meaning the
schedule:runcommand waits for each task to finish. You can userunInBackground()to spawn a separate process so the scheduler doesn’t block. - Output handling – The scheduler captures output and can send it to a file, email, or a callback via
sendOutputTo(),emailOutputTo(), etc. - Post-execution – After all due events run, the scheduler cleans up and exits. The cron daemon waits for the next minute.
How to Choose the Right Scheduling Method
Laravel offers several ways to define a scheduled event. The most common are:
Schedule::command('email:send')– runs an Artisan command.Schedule::job(SomeJob::class)– dispatches a queued job.Schedule::call(function () { ... })– runs a closure.Schedule::exec('command')– runs a system command.
For frequency, use methods like daily(), hourly(), everyFiveMinutes(), or a raw cron expression via cron('*/5 * * * *'). Choose the method that matches the task: use command for Artisan tasks, job for queued work, and call for simple closures. For tasks that must run on a specific server in a multi-server environment, use onOneServer().
Common Problems and Misconceptions
A frequent issue is that the scheduler doesn’t run at all because the cron entry is missing or the path is wrong. Another is that tasks run twice because you have both the scheduler cron and a separate cron line for the same task. Overlapping is also common: if a task takes longer than the interval, it may start again before finishing. Use withoutOverlapping() to prevent that.
A misconception is that the scheduler runs tasks at the exact second the cron fires. Actually, cron has a resolution of one minute, so tasks are executed at the start of the minute, but the exact second depends on system load. Also, the scheduler does not run tasks in parallel by default; it runs them sequentially. If you need parallel execution, use runInBackground() or queue the tasks.
Safety and Reliability
When using the scheduler, ensure your cron entry points to the correct PHP binary and project path. Use the full path to PHP if needed. Also, make sure the scheduler runs as a user with permission to write to the storage directory, because it creates lock files for overlapping prevention. For critical tasks, consider logging output to a file so you can debug failures. The scheduler will not retry failed tasks automatically; you need to handle retries in your task logic or use monitoring.
Alternatives to the Laravel Scheduler
If you cannot use cron (e.g., on shared hosting), you can use Laravel’s schedule:work command, which runs the scheduler in the foreground and sleeps between checks. This is useful for development. Another alternative is to use a queue worker with delayed jobs, but that requires a queue driver. For complex scheduling, you might use a dedicated job scheduler like Jenkins or GitHub Actions, but those add external dependencies. The built-in scheduler is usually sufficient for most applications.
Frequently Asked Questions
Why is my scheduled task not running? Check that the cron entry is correct and that the scheduler is actually being invoked. Run php artisan schedule:list to see registered events, and php artisan schedule:run manually to see any errors. Also verify the timezone in config/app.php.
How do I run a scheduled task every 30 seconds? The scheduler is limited to one-minute resolution because cron runs every minute. To run every 30 seconds, you need to run the scheduler every minute and use a condition inside the task to check if 30 seconds have passed, or use a custom loop with schedule:work.
Can I run scheduled tasks on a specific server in a multi-server setup? Yes, use the onOneServer() method. It uses a shared cache or database to ensure only one server runs the task. You must configure a cache or database driver that supports atomic locks, like Redis or the database cache.
What does withoutOverlapping() actually do? It creates a lock file in the storage directory before running the task and removes it after. If the lock file exists when the task is due, the scheduler skips it. This prevents two instances of the same task from running simultaneously.
How do I test scheduled tasks? Use the Schedule::test() method in a test, or run php artisan schedule:run with the --verbose flag to see what runs. You can also use Schedule::call(...)->everyMinute() and run the scheduler manually to see output.
Related
Formula used
in t | Finish time | min | 50 | 0 in d | Distance | km | 10 | 0 | 100000 out pace | Average pace | min/km | t / d | 2 out speed | Average speed | km/h | d / (t / 60) | 2
Each line is one input (in, sel, list) or one result (out: label, unit, formula, decimals). How the calculators work
Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.
More cards in this drawer
- Valheim Server Not Showing in Community List Fixes
- DisplayPort vs HDMI: Which Cable Should You Use?
- Soundbar vs 2.1 Speaker System: Which Is Better?
- Mouse Moving on Its Own? Causes & Fixes
- Slack Channels for Construction Projects: Setup Guide
- Surface Won’t Turn On: Quick Fixes1.8 h