Brand3000's avatar

Schedule, withoutOverlapping

Hi folks! I have two tasks added like that:

        $schedule->command('all:sync')
            ->cron('*/5 * * * *')->withoutOverlapping();
        $schedule->command('employee:sync')
            ->everyTenMinutes()->withoutOverlapping();

I've noticed that when it comes to every 10 mins, my second command is waiting for finishing the first one. However, if the second command is still running and time comes to the next 5 mins, the first command runs properly. Both scripts are working in parallel. Why does it behave like that? I supposed that both the commands would work in parallel every ten minutes and only the first one every 5 mins.

0 likes
1 reply
LaryAI's avatar
Level 58

The behavior you're observing is due to how the withoutOverlapping() method works in Laravel's task scheduling. This method prevents a scheduled task from starting if the previous instance of the task is still running. However, it does not coordinate between different tasks; it only applies to the task it is called on.

Here's a breakdown of what's happening:

  1. First Command (all:sync): This command is scheduled to run every 5 minutes. The withoutOverlapping() method ensures that if a previous instance of all:sync is still running, a new instance will not start.

  2. Second Command (employee:sync): This command is scheduled to run every 10 minutes. Similarly, withoutOverlapping() ensures that if a previous instance of employee:sync is still running, a new instance will not start.

The key point is that withoutOverlapping() does not prevent all:sync and employee:sync from running at the same time. It only prevents multiple instances of the same command from overlapping.

Solution

If you want to ensure that employee:sync does not start if all:sync is running, you would need to implement a custom locking mechanism. However, if the goal is simply to understand the behavior, then the current setup is working as intended.

If you want to ensure that both commands do not run at the same time, you could use a shared lock file or database entry to manage this manually. Here's a basic example using a file-based lock:

$schedule->command('all:sync')
    ->cron('*/5 * * * *')
    ->withoutOverlapping()
    ->before(function () {
        // Create a lock file
        file_put_contents(storage_path('locks/all_sync.lock'), 'locked');
    })
    ->after(function () {
        // Remove the lock file
        unlink(storage_path('locks/all_sync.lock'));
    });

$schedule->command('employee:sync')
    ->everyTenMinutes()
    ->withoutOverlapping()
    ->when(function () {
        // Check if the lock file exists
        return !file_exists(storage_path('locks/all_sync.lock'));
    });

In this example, employee:sync will only run if the lock file created by all:sync does not exist, effectively preventing them from running simultaneously. Adjust the logic as needed for your specific requirements.

Please or to participate in this conversation.