定時任務 Scheduled Tasks 是 Laravel 提供的組件之一,稍微上點規模的項目應該都會用到,好比開發微信應用時經過定時任務去刷新access token,好比天天定時發推送提現用戶要記得簽到。對於定時任務的基本用法,官網文檔已經描述得很詳細了,這裏再也不多說。php
本文主要是介紹定時任務在實際應用中的兩個小技巧:laravel
先簡單介紹一下 Laravel 定時任務組件的基本原理:git
當cli初始化完畢以後,系統會調用 App\Console\Kernel::schedule
方法,也就是咱們定義定時任務列表的地方,這個方法裏每調用一次 $schedule->command()
就會生成一個 Illuminate\Console\Scheduling\Event
對象並保存在 $schedule->events
數組裏。當執行 php artisan scheduled:run
時,系統會遍歷 $schedule->events
,把當前時間須要執行的任務放在一個集合中,最後依次 串行執行 這些任務。github
這樣作在大多數狀況下是沒有問題的,但有一些特殊的狀況,好比在每月的第一天要給100W個用戶發送郵件,同一批次的定時任務必須等到這些郵件所有發送完畢以後纔會被執行,假如這些任務裏有對執行時間十分敏感的任務,比每5分鐘一次的數據快照,就會致使那個時間點數據的缺失。數組
這種狀況下若是定時任務可以並行執行,就不會有這樣的問題。Laravel 實際上提供瞭解決方案,但很奇怪文檔裏面並無提到,就是 runInBackground
方法,在定義定時任務時 $schedule->command('foo:bar')->everyMinutes()->runInBackground();
就能夠了。服務器
隨着業務邏輯的增多,定時任務也會愈來愈多,定時任務服務器的負載也會愈來愈高,甚至致使任務執行緩慢,然而咱們卻只能在一臺服務器上設置定時任務,若是在多臺服務器上同時配置了定時任務,還會致使定時任務的重複執行。這個時候咱們但願可以像隊列那樣,將定時任務分散到多臺服務器上。微信
截止 v5.4.15,Laravel 尚未提供內置方案來解決這個問題,但只須要簡單的改造就能夠實現咱們須要的效果。首先咱們把將每一個定時任務裏 handle
方法提取出來建立一個新的Job並繼承 ShouldQueue
,而後在定時任務的 handle
裏直接 dispatch
對應的Job便可,這樣本來的業務邏輯就會被隊列處理掉,當系統有多臺服務器在處理隊列時,也就實現了咱們須要的負載均衡。負載均衡
可是這樣畢竟仍是麻煩,每一個定時任務都要建立一個Command和一個Job,太費勁,因而我提交了一個 Proposal ,目前已經實現而且merge入5.4分支,相信下個版本你們就能用上了。用法也很簡單,只須要建立一個繼承 ShouldQueue
的Job,而後在App\Console\Kernel::schedule
方法裏定義spa
$schedule->job(new FooBarJob())->everyMinutes();
就能夠了code