Parfois, l'exécution d'une tâche planifiée peut prendre plus de temps que nous le pensons, ce qui posera un problème——Actuellement avant que la tâche ne soit terminée , une autre tâche identique sera exécutée, entraînant une duplication de tâches. Par exemple, imaginez que nous exécutons une tâche qui génère un rapport toutes les minutes. Après un certain temps, la quantité de données devient si importante que le temps d'exécution dépasse 1 minute. Cela entraînera la génération d'une autre tâche avant l'exécution. la tâche précédente est terminée. La même tâche commence à s'exécuter.
Dans la plupart des cas, il n'y a pas de problème, mais parfois nous devons éviter cette situation pour garantir que nous obtenons les données correctes. Dans Laravel, nous pouvons le gérer via la méthode withoutOverlapping
:
$schedule->command('mail:send')->withoutOverlapping();
Laravel vérifiera l'attribut ConsoleSchedulingEvent::withoutOverlapping
Si la valeur est vraie, un mutex sera créé pour cette tâche, et Cette tâche ne sera que. effectuée si le mutex peut être créé.
C'est l'explication la plus drôle que j'ai trouvée en ligne :
Lorsque nous sommes en réunion et que nous avons une discussion animée, je sors un poulet hurlant de mon bureau. Seule la personne qui tient le Poulet Screaming peut parler, si vous ne tenez pas le Poulet Screaming, vous ne pouvez pas parler. Vous ne pouvez demander des instructions à l'hôte de la réunion, et vous ne pouvez parler que lorsque vous obtenez le poulet hurlant, sinon vous ne pouvez qu'attendre. Lorsque vous avez fini de parler, remettez le poulet hurlant à l'hôte de la réunion, qui le donnera à la prochaine personne qui prendra la parole. Cela garantira que les gens ne se parlent pas, mais aussi qu'ils auront leur propre temps pour parler.
Remplacez le poulet hurlant par un verrou mutex et les personnes par des fils. Vous avez essentiellement le concept de base d'un verrou mutex.
-- https://stackoverflow.com/questions/34524/...
Laravel exécute la tâche pour le premier time Un verrou mutex sera créé, puis chaque fois qu'une tâche est exécutée, il sera vérifié si le verrou mutex existe. La tâche ne sera exécutée que lorsque le verrou mutex n'existe pas. Voici la méthode withoutOverlapping
:
public function withoutOverlapping() { $this->withoutOverlapping = true; return $this->then(function () { $this->mutex->forget($this); })->skip(function () { return $this->mutex->exists($this); }); }
Laravel crée une méthode de rappel de filtre pour indiquer au gestionnaire de planification d'ignorer les tâches pour lesquelles le mutex existe toujours, et crée également un rappel qui efface le mutex après avoir terminé l'instance de tâche. .rappel. En même temps, avant d'exécuter la tâche, Lravel effectuera la série de vérifications suivante dans la méthode ConsoleSchedulingEvent::run()
:
if ($this->withoutOverlapping && ! $this->mutex->create($this)) { return; }
Alors d'où viennent les propriétés du verrou mutex ?
Quand ConsoleSchedulingSchedule
est instancié, Laravel vérifiera si ConsoleSchedulingMutex
est lié au conteneur, si c'est le cas il l'instanciera, sinon il utilisera ConsoleSchedulingCacheMutex
$this->mutex = $container->bound(Mutex::class) ? $container->make(Mutex::class) : $container->make(CacheMutex::class);
Maintenant, quand le le gestionnaire de tâches enregistre un événement, il passera dans l'instance mutex :
$this->events[] = new Event($this->mutex, $command);
Laravel utilise par défaut un mutex implémenté dans le cache, mais vous pouvez l'implémenter et le remplacer vous-même.
La classe CacheMutex n'a que 3 méthodes simples, qui utilisent le nom du mutex d'événement comme clé de cache :
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()); }
Comme nous l'avons vu auparavant, le gestionnaire enregistre un rappel post-exécution pour garantir que le mutex est supprimé lorsque la tâche est terminée. Pour une commande dans le système, sa suppression peut déjà être garantie. Cependant, pour une tâche avec une méthode de rappel, le script peut se terminer lorsque le rappel est exécuté. Par conséquent, afin d'éviter cette situation, le code suivant est ajouté à la méthode ConsoleSchedulingCallbackEvent::run()
pour garantir que le mutex peut être supprimé normalement lorsque. la tâche est fermée de manière inattendue :
register_shutdown_function(function () { $this->removeMutex(); });
Pour plus d'articles techniques liés à Laravel, veuillez visiter la colonne Tutoriel Laravel pour apprendre !
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!