public function withoutOverlapping() {     $this->withoutOverlapping = true;     return $this->then(function () {         $this->mutex->forget($this);     })->skip(function () {         return $this->mutex->exists($this);     }); }

登录后复制

Laravel创建了一个过滤回调方法来告诉计划管理器忽略互斥锁仍然存在的任务,同时也创建了一个在完成任务实例后清除互斥锁的回调。同时,在执行任务之前,Lravel会在Console\Scheduling\Event::run()方法中依次执行下面一系列的检查:

if ($this->withoutOverlapping && ! $this->mutex->create($this)) {
    return;
}
登录后复制

那么互斥锁的属性是从哪里来的呢?

Console\Scheduling\Schedule被实例化的时候,Laravel会检查Console\Scheduling\Mutex是否绑定到了容器,如果是那么就会实例化它,否则会使用Console\Scheduling\CacheMutex

$this->mutex = $container->bound(Mutex::class)
                        ? $container->make(Mutex::class)
                        : $container->make(CacheMutex::class);
登录后复制

现在当任务管理器在注册事件的时候会将互斥锁的实例一并传进去:

$this->events[] = new Event($this->mutex, $command);
登录后复制

Laravel默认使用了缓存实现的互斥锁,但是你可以自己实现并替换它。

缓存版的互斥锁

CacheMutex类只有3个简单的方法,它使用了事件互斥锁的名字作为缓存的键值:

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());
}
登录后复制

就像我们之前看过的,管理器注册了一个执行后回调来保证任务执行完毕的时候移除互斥锁,对于一个系统里的命令来说也许已经可以确保移除了。但是对于一个回调方法的任务来说脚本可能在执行回调的时候结束,因此为了避免这种情况在Console\Scheduling\CallbackEvent::run()方法中加入了下面的代码确保互斥锁在任务意外关闭的时候能够正常移除:

register_shutdown_function(function () {
    $this->removeMutex();
});
登录后复制

更多Laravel相关技术文章,请访问Laravel教程栏目进行学习!

以上就是Laravel是怎样防止你的定时任务重复执行的的详细内容,更多请关注其它相关文章!