Sometimes the execution of a scheduled task may take longer than we imagine, which will cause a problem——Currently Before the task is completed, another identical task will be executed, resulting in task duplication.For example, imagine that we execute a task that generates a report every minute. After a period of time, the amount of data becomes large and the execution time exceeds 1 minute. This will cause another task to be generated before the previous task is completed. The same task starts executing.
In most cases there is no problem, but sometimes we need to avoid this situation to ensure correct data. In Laravel we can handle it through thewithoutOverlapping
method:
$schedule->command('mail:send')->withoutOverlapping();
Laravel will check theConsole\Scheduling\Event::withoutOverlapping
attribute, if the value is true then A mutex will be created for this task, and the task will only be executed if the mutex can be created.
This is the funniest explanation I've found online:
When we're in a meeting and having a heated discussion, I pull out a Screaming Chicken from my desk. Only the person holding the Screaming Chicken can speak, if you are not holding the Screaming Chicken you cannot speak. You can only ask the meeting host for instructions, and you can only speak when you get the Screaming Chicken, otherwise you can only wait. When you finish speaking, return the Screaming Chicken to the meeting host, who will give the Screaming Chicken to the next person to speak. This will ensure that people are not talking over each other but also that they will have their own time to speak.
Replace the screaming chicken with a mutex lock and the person with a thread. You basically have the basic concept of a mutex.
--https://stackoverflow.com/questions/34524/...
Laravel performs tasks for the first time A mutex lock will be created, and then every time a task is executed, it will be checked to see if the mutex lock exists. The task will only be executed when the mutex lock does not exist. Here is thewithoutOverlapping
method:
public function withoutOverlapping() { $this->withoutOverlapping = true; return $this->then(function () { $this->mutex->forget($this); })->skip(function () { return $this->mutex->exists($this); }); }
Laravel creates a filter callback method to tell the schedule manager to ignore tasks for which the mutex still exists, and also creates a method to clean up after completing the task instance. Mutex callback. At the same time, before executing the task, Lravel will perform the following series of checks in theConsole\Scheduling\Event::run()
method:
if ($this->withoutOverlapping && ! $this->mutex->create($this)) { return; }
Then the properties of the mutex are Where did it come from?
WhenConsole\Scheduling\Schedule
is instantiated, Laravel will check whetherConsole\Scheduling\Mutex
is bound to the container, and if so, it will be instantiated Change it, otherwise it will useConsole\Scheduling\CacheMutex
$this->mutex = $container->bound(Mutex::class) ? $container->make(Mutex::class) : $container->make(CacheMutex::class);
Now when the task manager registers the event, it will pass the mutex instance together:
$this->events[] = new Event($this->mutex, $command);
Laravel uses a cache-implemented mutex by default, but you can implement and replace it yourself.
The CacheMutex class has only 3 simple methods, which uses the name of the event mutex as the cache key:
public function create(Event $event) { return $this->cache->add($event->mutexName(), true, 1440); } public function exists(Event $event) { return $this->cache->has($event->mutexName()); } public function forget(Event $event) { $this->cache->forget($event->mutexName()); }
Just As we have seen before, the manager registers a post-execution callback to ensure that the mutex is removed when the task is completed, which may already be guaranteed for a command in the system. However, for a callback method task, the script may end when the callback is executed. Therefore, in order to avoid this situation, the following code is added to theConsole\Scheduling\CallbackEvent::run()
method to ensure interaction. The repulsion lock can be removed normally when the task is closed unexpectedly:
register_shutdown_function(function () { $this->removeMutex(); });
For more Laravel related technical articles, please visit theLaravel Tutorialcolumn to learn!
The above is the detailed content of How Laravel prevents your scheduled tasks from being executed repeatedly. For more information, please follow other related articles on the PHP Chinese website!