譯文GitHub https://github.com/yuansir/diving-laravel-zhphp
原文連接 https://divinglaravel.com/task-scheduling/preventing-overlappingios
Sometimes a scheduled job takes more time to run than what we initially expected, and this causes another instance of the job to start while the first one is not done yet, for example imagine that we run a job that generates a report every minute, after sometime when the data gets huge the report generation might take more than 1 minute so another instance of that job starts while the first is still ongoing.laravel
有時一個預約的工做須要比咱們最初預期的更多的時間運行,這樣會致使另一個工做的實例開始,而第一個尚未完成,例如,咱們運行一個每分鐘生成報告的工做有時候當數據變大時,報表生成可能須要1分鐘以上,這樣就能夠在第一個還在進行時啓動該做業的另外一個實例。git
In most scenarios this is fine, but sometimes this should be prevented in order to guarantee correct data or prevent a high server resources consumption, so let's see how you can prevent such scenario in laravel:github
在大多數狀況下,這是很好的,但有時候應該防止這種狀況,以保證正確的數據或防止高的服務器資源消耗,因此讓咱們看看如何防止這種狀況在laravel中發生:緩存
$schedule->command('mail:send')->withoutOverlapping();
Laravel will check for the Console\Scheduling\Event::withoutOverlapping
class property and if it's set to true it'll try to create a mutex for the job, and will only run the job if creating a mutex was possible.服務器
Laravel將檢查 Console\Scheduling\Event::withoutOverlapping
類屬性,若是設置爲true,它將嘗試爲做業建立互斥,而且只有在建立互斥的狀況下才能運行該做業。app
Here's the most interesting explanation I could find online:ide
這是我能夠在網上找到最有趣的解釋:this
When I am having a big heated discussion at work, I use a rubber chicken which I keep in my desk for just such occasions. The person holding the chicken is the only person who is allowed to talk. If you don't hold the chicken you cannot speak. You can only indicate that you want the chicken and wait until you get it before you speak. Once you have finished speaking, you can hand the chicken back to the moderator who will hand it to the next person to speak. This ensures that people do not speak over each other, and also have their own space to talk. Replace Chicken with Mutex and person with thread and you basically have the concept of a mutex.-- https://stackoverflow.com/questions/34524/what-is-a-mutex/34558#34558
當我在工做中進行熱烈的討論時,我使用一隻橡膠雞,我在這樣的場合放在桌子上。 持有雞的人是惟一被容許談話的人。 若是你不握雞,你不會說話。 你只能指示你想要雞,等到你說話以前才能獲得它。 一旦你完成演講,你能夠將雞回到主持人,他將把它交給下一我的說話。 這樣能夠確保人們互不說話,也有本身的空間。 用線替換雞與互斥和人,你基本上有一個互斥的概念。
-- https://stackoverflow.com/questions/34524/what-is-a-mutex/34558#34558
So Laravel creates a mutex when the job starts the very first time, and then every time the job runs it checks if the mutex exists and only runs the job if it doesn't.
因此看成業第一次啓動時,Laravel建立一個互斥,而後每次做業運行時,它檢查互斥是否存在,只有在沒有工做的狀況下運行。
Here's what happens inside the withoutOverlapping
method:
這裏是 withoutOverlapping
方法中作的事
public function withoutOverlapping() { $this->withoutOverlapping = true; return $this->then(function () { $this->mutex->forget($this); })->skip(function () { return $this->mutex->exists($this); }); }
So Laravel creates a filter-callback method that instructs the Schedule Manager to ignore the task if a mutex still exists, it also creates an after-callback that clears the mutex after an instance of the task is done.
所以,Laravel建立一個filter-callback方法,指示Schedule Manager忽略任務,若是互斥仍然存在,它還會建立一個在完成任務實例後清除互斥的回調。
Also before running the job, Laravel does the following check inside the Console\Scheduling\Event::run()
method:
在運行該做業以前,Laravel會在Console\Scheduling\Event::run()
方法中進行如下檢查:
if ($this->withoutOverlapping && ! $this->mutex->create($this)) { return; }
While the instance of Console\Scheduling\Schedule
is being instantiated, laravel checks if an implementation to the Console\Scheduling\Mutex
interface was bound to the container, if yes it uses that instance but if not it uses an instance of 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);
Now while the Schedule Manager is registering your events it'll pass an instance of the mutex:
如今,Schedule Manager正在註冊你的事件,它會傳遞互斥的一個實例:
$this->events[] = new Event($this->mutex, $command);
By default Laravel uses a cache-based mutex, but you can override that and implement your own mutex approach & bind it to the container.
默認狀況下,Laravel使用基於緩存的互斥,但您能夠覆蓋它並實現本身的互斥方法並將其綁定到容器。
The CacheMutex
class contains 3 simple methods, it uses the event mutex name as a cache key:
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()); }
As we've seen before, the manager registers an after-callback that removes the mutex after the task is done, for a task that runs a command on the OS that might be enough to ensure that the mutex is cleared, but for a callback task the script might die while executing the callback, so to prevent that an extra fallback was added in Console\Scheduling\CallbackEvent::run()
:
如前所述,管理器註冊一個在完成任務以後刪除互斥的回調,對於在操做系統上運行命令的任務可能足以確保互斥被清除,可是對於回調 執行回調時腳本可能會死機,因此爲了防止這種狀況在 Console\Scheduling\CallbackEvent::run()
中添加了一個額外的回退:
register_shutdown_function(function () { $this->removeMutex(); });
轉載請註明: 轉載自Ryan是菜鳥 | LNMP技術棧筆記
若是以爲本篇文章對您十分有益,何不 打賞一下
本文連接地址: 剖析Laravel計劃任務--避免重複