翻译GitHubhttps://github.com/yuansir/diving-laravel-zh原文链接https://divinglaravel.com/task-scheduling/preventing-overlappingSometimesascheduledjobtakesmore运行时间比我们最初预期的要长,这会导致作业的另一个实例开始,而第一个实例尚未完成,例如假设我们运行一个作业,在数据变得庞大的某个时间后每分钟生成一份报告报告生成可能需要1分钟以上,因此该作业的另一个实例会在第一个作业仍在进行时启动。而第一个还没有结束,比如我们跑一个每分钟生成一个报表的job,有时候当数据变大的时候,报表的生成可能需要1分钟以上,所以可以在第一个的时候开始job还在进行另一个实例。在大多数情况下这很好,但有时为了保证正确的数据或防止高服务器资源消耗应该避免这种情况,所以让我们看看如何在laravel中防止这种情况:,但有时应该防止这种情况以保证正确的数据或者防止高服务器资源消耗,所以让我们看看如何在laravel中防止这种情况发生:$schedule->command('mail:send')->withoutOverlapping();Laravel将检查Console\Scheduling\Event::withoutOverlapping类属性,如果它设置为true,它将尝试为作业创建一个互斥锁,并且只有在创建互斥锁是可能的情况下才会运行该作业。Laravel将检查Console\Scheduling\Event::withoutOverlapping类属性,如果设置为true,它将尝试为作业创建互斥体,并且只有在创建互斥体时才能运行作业。但什么是互斥体?但是上面是互斥体?这是我能在网上找到的最有趣的解释:当我在工作中进行激烈的讨论时,我会用一只橡皮鸡,我把它放在办公桌上以备不时之需。拿着鸡的人是唯一被允许说话的人。不抱鸡就不能说话。只能表示要鸡,等拿到了再开口。发言结束后,可以把鸡还给主持人,主持人再交给下一个发言的人。这样可以确保人们不会互相交谈,也有自己的交谈空间。将Chicken替换为Mutex,将person替换为thread,您基本上就有了互斥锁的概念。--https://stackoverflow.com/questions/34524/what-is-a-mutex/34558#34558当我在工作时当在进行热烈的讨论时,我会用橡皮鸡,在这种场合我会把它放在桌子上。拿着鸡的人是唯一被允许说话的人。不抱鸡就不能说话。你只能表明你想要鸡肉,等你说话才能拿到。说完,把鸡还给主人,主人再传给下一个说话的人。这样既保证了人与人之间不会说话,也有自己的空间。用互斥体代替鸡,用线代替人,您基本上就有了互斥体的概念。--https://stackoverflow.com/questions/34524/what-is-a-mutex/34558#34558所以Laravel在作业第一次启动时创建一个互斥量,然后每次作业运行时它检查互斥量是否存在并且仅在不存在时才运行该作业。所以当作业第一次启动时,Laravel会创建一个互斥量,然后每次作业运行时,它会检查互斥量是否存在,只有在没有作业时才会运行。这是withoutOverlapping方法内部发生的事情:这是withoutOverlapping方法中完成的事情publicfunctionwithoutOverlapping(){$this->withoutOverlapping=true;返回$this->then(function(){$this->mutex->forget($this);})->skip(function(){return$this->mutex->exists($this);});}所以Laravel创建了一个过滤器回调方法,如果互斥量仍然存在,它会指示计划管理器忽略任务,它还会创建一个后回调,在任务实例完成后清除互斥量。因此,Laravel创建了一个filter-callback方法来指示ScheduleManager忽略任务,如果mutex仍然存在,它也会在完成任务实例后创建一个清除mutex的回调。同样在运行作业之前,Laravel在Console\Scheduling\Event::run()方法中执行以下检查:在运行作业之前,Laravel在Console\Scheduling\Event::run()方法中执行以下检查:如果($this->withoutOverlapping&&!$this->mutex->create($this)){return;}mutex属性从何而来?当Console\Scheduling\Schedule的实例被实例化时,laravel检查Console\Scheduling\Mutex接口的实现是否绑定到容器,如果是,它使用该实例,但如果不是,它使用Console\Scheduling\的实例CacheMutex:当Console\Scheduling\Schedule实例被实例化时,laravel会检查Console\Scheduling\Mutex接口的实现是否绑定到容器,如果是,则使用该实例,如果不是,则使用Console\Scheduling\CacheMutex实例:$this->mutex=$container->bound(Mutex::class)?$container->make(Mutex::class):$container->make(CacheMutex::class);现在,当计划管理器正在注册您的事件时,我t将传递一个互斥锁的实例:现在计划管理器正在注册您的事件,它将传递一个互斥锁的实例:$this->events[]=newEvent($this->mutex,$command);默认情况下,Laravel使用基于缓存的互斥锁,但你可以覆盖它并实现你自己的互斥锁方法并将其绑定到容器。方法并将其绑定到容器基于缓存的互斥体CacheMutex类包含3个简单方法,它使用事件互斥体名称作为缓存键:CacheMutex类包含3个简单方法,它们使用事件互斥体名称作为缓存键:publicfunctioncreate(Event$event){return$this->cache->add($event->mutexName(),true,1440);}publicfunctionexists(Event$event){return$this->cache->has($event->mutexName());}publicfunctionforget(Event$event){$this->cache->forget($event->mutexName());}任务完成后删除互斥正如我们之前看到的,管理器注册了一个after-在任务完成后删除互斥量的回调,对于在操作系统上运行命令的任务可能足以确保清除互斥量,但对于回调任务,脚本可能会在执行回调时终止,因此防止在Console\Scheduling\CallbackEvent::run()中添加额外的回退:如前所述,管理器注册一个回调,在完成任务后删除互斥量,对于任务that在操作系统上运行命令可能足以确保清除互斥量,但对于执行回调的回调,脚本可能会冻结,因此要在Con中防止这种情况sole\Scheduling\CallbackEvent::run()添加了一个额外的回退:register_shutdown_function(function(){$this->removeMutex();});转载请注明:转载自瑞安是菜鸟|LNMP技术栈笔记如果觉得这篇文章对你很有帮助,不妨打赏一下本文链接地址:分析Laravel计划任务-避免重复
