定時調度器是什么
laravel默認提供了一個命令定時任務的功能,在其他的php框架下面,沒有這個定時任務,我們要跑一些異步腳本怎么操作呢,只能依賴我們系統(tǒng)提供的crontab來做,這就導致我們每次發(fā)版本新增定時任務都要去服務器更改crontab代碼,獲取更新這個配置。
執(zhí)行命令是php artisan schedule:run
來執(zhí)行,那放在哪里執(zhí)行呢,沒錯這個調起還是需要依賴我們crontab來執(zhí)行,但是只需要配置一次,后續(xù)所有定時任務都在我們業(yè)務代碼進行控制
場景
我們有一個導入數(shù)據(jù)的定時任務
//每分鐘導入庫數(shù)據(jù) $schedule->command(self::SIGNATURE)->withoutOverlapping()->everyMinute()->runInBackground();
這里導入長時間最好使用runInBackground(),表示異步執(zhí)行,其實就是在shell腳本的末尾加上 符號,在linux上完全依賴系統(tǒng)的方式完成。
這里使用了withoutOverlapping() 表示在同一時刻只能有一個任務執(zhí)行,主要邏輯使用的是排它鎖實現(xiàn),依賴于我們cache的driver,我這里使用的是redis,后面作為鎖的過期直接redis提供的key過期來做。
出現(xiàn)問題
這個任務在正常情況下都是非常完美的,因為同一時刻只有一個再跑,跑完就可以,但是一個場景出現(xiàn)
有一天我們的qa同學剛部署環(huán)境后,我們服務端就在默默的導入庫了,因為使用withoutOverlapping($expire_at=1440)
這個時候在redis就有一個鎖產(chǎn)生了,這個默認帶參數(shù)是鎖的過期時間,默認是一天,然后因為我們docker環(huán)境需要更改參數(shù)然后進行后端server服務的重啟,我們重啟也是比較暴力,就是直接發(fā)送kill的信號,導致所有在里面跑的進程瞬間kill,而這時候我們的redis的鎖缺還存在,而且是1440分鐘左右,那當我們server再啟動后,發(fā)現(xiàn)鎖一直存在,沒辦法進行后續(xù)的操作了,只能等著。
解決
那我把鎖的時間減少行不行,原來1天,我改成30分鐘,沒問題,開始第一版方案我們也是這樣做,官方也是可以這樣做的。
后來我們一想,能否做到一個監(jiān)控程序呢,進程退出后立馬監(jiān)控到過期呢,這樣就不用固定一個時間,這當然是所有軟件開發(fā)者理想狀態(tài):要你開你就開,我掛了鎖也就去掉了,不論正常與否。
解決方案
說明:
代碼實現(xiàn)
代碼實現(xiàn)總是那么蒼白無力哈,這里就寫一個laravel的擴展來做,好處就是不影響我們主體的任何代碼就完成了,我們的laravel可以隨意升級。
github地址:github.com/zzh78727258…
composer地址:packagist.org/packages/ze…
總結
整體實現(xiàn)沒有使用判斷進程是否存在的ps grep等命令,因為我們docker環(huán)境不一定支持這些命令,只是用簡單的pid與parent_id做對比。
laravel的在命令開始于結束都進行鉤子方式,我們在Listener下面進行監(jiān)聽即可
public function subscribe($events) { $events->listen( [ CommandStarting::class, // 命令開始的時候 ], __CLASS__ . '@handle' ); }
整體代碼是基于laravel擴展化的,不會影響laravel的升級操作。
好了,以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對腳本之家的支持。
下一篇:php精度計算的問題解析