Currently Available: Need a skilled Software Developer for your next project?
Categories
Laravel

How to Prevent Overlapping Scheduled Tasks in Laravel

In Laravel, a scheduled task is a command or callback that the scheduler runs at a set time. A server cron entry calls Laravel’s scheduler, which checks which tasks are due. If a task takes longer than its interval, the next scheduled run can start before the earlier run finishes.

Use Laravel’s withoutOverlapping() method to stop a scheduled task from starting while an earlier run of that same task is still active. The method protects only that task. Different scheduled tasks need to check a shared lock if they must never run at the same time.

Prevent a task from overlapping with itself

Call withoutOverlapping() on the scheduled task that needs protection. In Laravel versions that define schedules in App\Console\Kernel, the code can look like this:

protected function schedule(Schedule $schedule): void
{
    $schedule->command('reports:generate')
        ->hourly()
        ->withoutOverlapping();
}

The method prevents another run of reports:generate while its previous run is still running, but other scheduled commands can run at the same time. Laravel’s older scheduling documentation describes the scheduler setup. Check the documentation for your installed Laravel version for the current file location and scheduling API details.

The server still needs to call the scheduler. A common setup uses one cron entry to run php artisan schedule:run every minute:

* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1

Laravel then runs each task when its schedule is due. If a task appears to run more than once, check its schedule and whether more than one server is calling the scheduler.

Coordinate different scheduled tasks with a shared lock

withoutOverlapping() protects one scheduled task from another run of itself. It does not make separate tasks mutually exclusive. For example, adding the method to both all:sync and employee:sync still allows those two commands to run in parallel, as a Laravel community discussion explains.

When two different commands must not run at the same time, have each acquire the same lock before it starts work. Both commands can use the same database record or lock file to represent the lock. The first command to acquire it proceeds; the other exits or waits. The command that acquired it should release it when it finishes.

A community lock-file example is only a starting point; it does not describe built-in framework behavior. A command that crashes before releasing its lock can leave the lock behind, and a file stored on one server does not coordinate commands running on another server unless they share that filesystem. Choose a lock location both commands can access, and decide how your implementation handles locks left behind after failures.

Keep scheduler locks separate from queue-job locks

Scheduled tasks and queued jobs use different mechanisms. The scheduler runs commands on a timetable; a queue worker runs jobs placed on a queue. If a scheduled command dispatches jobs, preventing the command from overlapping does not by itself prevent two copies of a queued job from running at once.

Laravel provides a separate WithoutOverlapping queue middleware. It uses a lock key for a job. Use releaseAfter() to delay retrying a job that cannot acquire the lock. Use dontRelease() to delete that job without retrying it. Other options set a lock expiration or add a key prefix. Use the scheduler method to protect a scheduled task, and queue middleware to protect job execution.

What I'm building

Delegate tasks. Get software.

Give Vroni a GitHub issue, bug report, spec, or rough idea. It reads the repo, plans the change, writes code, runs checks, and works toward a review-ready pull request.

Take a look at vroni.com

Email updates

Usually a new article and a few links I found interesting.

No spam. Unsubscribe with one click.

Leave a Reply

Your email address will not be published. Required fields are marked *