基本介绍
有时候一个定时任务执行需要的时间可能会比我们想象的要长,这就会引起一个问题 —— **当前任务还没有执行完毕的时候另一个相同的任务也会执行,从而导致任务重复。**例如想象一下我们执行每分钟生成一次报告的任务,在经过一段时间后,数据量变得很大导致执行时间多于 1 分钟,这样就会导致在上一个任务还没结束的时候另一个相同的任务开始执行。
解决方法
大部分情况下是没有什么问题的,但是有时我们需要避免这种情况来保证获得正确的数据。在 Laravel 中我们可以通过withoutOverlapping
方法来进行处理:
$schedule->command('mail:send')->withoutOverlapping();
Laravel 会检查 Console\Scheduling\Event::withoutOverlapping
属性,如果该值为 true 那么将会针对这个任务创建一个互斥锁 (mutex),并且只有在可以创建互斥锁的情况下才会执行此任务。
什么是互斥锁?
这是我在网上找到的最有趣的解释:
当我们在开会进行激烈的讨论时,我会从我桌子里拿出来一个尖叫鸡。只有手里拿着尖叫鸡的人才能说话,如果你没有拿着尖叫鸡你是不能说话的。你只能向会议主持人请示,只有在你拿到尖叫鸡的时候你才能说话否则只能等待。当你讲话完毕的时候,将尖叫鸡还给会议主持人,主持人会将尖叫鸡给到下一个人来让其说话。这样会确保人们不会互相交谈,同时他们也会有自己的时间来进行讲话。
将尖叫鸡换成互斥锁,人换成线程。你基本上就有了一个互斥锁的基本概念。
– https://stackoverflow.com/questions/34524/what-is-a-mutex/34558#34558
原理分析
Laravel 在第一次执行任务的时候会创建一个互斥锁,然后在每次执行任务时会检查互斥锁是否存在,只有互斥锁不存在的时候任务才会执行。下面是 withoutOverlapping
方法:
public function withoutOverlapping()
{
$this->withoutOverlapping = true;