一. 什么是隊列
在構建 Web 應用程序時,你可能需要執行一些任務,例如解析文件,發送郵件,大量的數據計算等等,這些任務在典型的 Web 請求期間需要很長時間才能執行
。
慶幸的是,Laravel 可以創建在后臺運行
的隊列任務。 通過將時間密集型任務
移至隊列,你的應用程序可以以極快的速度響應
Web 請求,并為你的客戶提供更好的用戶體驗。
說人話:laravel可以輕松創建,后臺運行的隊列,再將耗時的任務移到隊列,減少用戶在頁面上的等待時間,提高用戶體驗。
二. 配置隊列驅動
隊列驅動 就是 以哪個方式來處理隊列任務。
常見的驅動如下:
1.sync 驅動 (同步)
.env 文件
編輯
QUEUE_CONNECTION=sync
特點是: 任務立即執行
,不進入隊列, 適合開發和測試環境
,請求會阻塞
直到任務完成
我一般是本地和測試
使用,如果使用這個,那就跟隊列沒什么關系了,直接同步執行
2. database 驅動
QUEUE_CONNECTION=database
數據庫驅動時,肯定首先需要創建數據表的。用來存儲隊列服務的。如下
php artisan queue:table
php artisan migrate
會創建兩個表,存儲任務數據
打開 config/queue.php
文件,配置一下
'database' => ['driver' => 'database','table' => 'jobs','queue' => 'default','retry_after' => 90,
],
特點是:使用的是數據庫存儲
任務,不需要單獨配置服務,有數據庫即可
,適合中小規模項目
3. redis 驅動 (推薦)
QUEUE_CONNECTION=redis
打開 config/queue.php
文件,配置一下
'redis' => ['driver' => 'redis','connection' => 'default','queue' => env('REDIS_QUEUE', 'default'),'retry_after' => 90,'block_for' => null,'after_commit' => false,],
注意:
利用 redis 做為驅動的話,前提一定要配置好 redis
。
特點:高性能
,適合生產環境
, 支持隊列優先級
其他的驅動,暫時不做說明,大家可以自己去研究下。
三.創建隊列任務
1. 生成任務類
php artisan make:job ProjectJob
生成的文件位于 app/Jobs/ProjectJob.php
2.任務類開發邏輯
<?phpnamespace App\Jobs;use App\Http\Services\ProjectService;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;/*** 項目工程隊列*/
class ProjectJob implements ShouldQueue
{use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;public array $reqData;/*** 任務支持錯誤,可嘗試的次數。** @var int*/public $tries = 5;/*** Create a new job instance.*/public function __construct($data = []){$this->reqData = $data;$this->onQueue('project-compute');}/*** Execute the job.*/public function handle(): void{$data = $this->reqData;// 開始發送郵件功能,大量耗時的任務開始編碼Log::info("===project-compute-Log===", [$data, $res]);}}
3.唯一任務實現
有時,希望這個隊列在任務時間點,只有一個任務的實例,只需要實現 ShouldBeUnique 即可。
<?phpuse Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Contracts\Queue\ShouldBeUnique;class ProjectJob implements ShouldQueue, ShouldBeUnique
{public $Project;/*** 唯一鎖將被釋放的秒數** @var int*/public $uniqueFor = 20;/*** 任務的唯一 ID*/public function uniqueId(): string{return $this->Project->id;}
}
如上:同一個 Project->id 在 20 秒內,都會被忽略,當 20 秒后,相同的id任務會再次分配到隊列
四. 分發隊列任務
分發,也就是怎么在控制器里面 去 將任務 丟到隊列。
1.基本分發方式
ProjectJob ::dispatch(['data':"123"]);
2.延遲分發,10分鐘后
ProjectJob ::dispatch(['data':"123"])->delay(now()->addMinutes(10));;
3.同步分發,立即執行
ProjectJob ::dispatchSync(['data':"123"]);
4. 指定隊列
ProjectJob ::dispatch(['data':"123"])->onQueue('high');
五. 隊列工作進程管理
1. 啟動隊列工作進程
php artisan queue:work
2. 常用選項
# 指定隊列連接
php artisan queue:work --queue=highphp artisan queue:work --queue=high,default
--queue=high,default
是啟動了一個工作進程
,但該進程會按照優先級處理多個隊列中的任務
。
3. 重啟隊列
在隊列的代碼修改了,那么就需要重啟隊列。
php artisan queue:restart
由于隊列任務是長期存在
的進程,如果不重新啟動
,他們不會注意
到代碼的更改。
可以通過發出 queue:restart
命令優雅地重新啟動所有進程
queue:restart 說明:
-
不是真正的進程重啟:
-
不會終止或重新創建
現有的隊列工作進程 -
不會改變進程ID
(PID)或端口 -
現有進程
會繼續完成
當前正在處理的任務
-
-
優雅重啟機制:
-
在存儲系統(緩存/數據庫)中
設置重啟標記
-
工作進程在完成當前任務后
檢查到標記
,會自行退出
-
進程管理器(如
Supervisor
)會自動重新啟動
新進程
-
注意:
我的隊列進程就是 用 Supervisor
托管的,所以在 queue:restart
后,Supervisor 會自動重啟
我的隊列進程。
當前隊列進程啟動后,在控制器內,丟入任務到隊列,隊列就會排隊處理任務了。
如下圖所示,隊列的處理日志。
六. 處理失敗的任務
在任務處理失敗時,隊列會先嘗試在運行幾次,見 2.任務類開發邏輯 的 tries 參數,超過
此嘗試次數后,它將被插入到 failed_jobs
數據庫表中
php artisan queue:failed-tablephp artisan migrate
可以使用 queue:failed-table
命令來創建遷移錯誤任務表
1.查看失敗任務
php artisan queue:failed
如圖:
2. 重試失敗的任務
#重試單個任務id
php artisan queue:retry ce7bb17c-cdd8-41f0-a8ec-7b4fef4e5ece# 重試多個任務id
php artisan queue:retry ce7bb17c-cdd8-41f0-a8ec-7b4fef4e5ece 91401d2c-0784-4f43-824c-34f94a33c24d# 重試指定隊列的所有失敗任務
php artisan queue:retry --queue=name#重試所有失敗任務
php artisan queue:retry all
執行后
3.清理失敗任務
#要刪除指定的失敗任務
php artisan queue:forget 91401d2c-0784-4f43-824c-34f94a33c24d# 刪除 failed_jobs 表中所有失敗任務
php artisan queue:flush
如圖
通過以上配置和使用方法,你可以充分利用Laravel隊列系統來提高應用性能和用戶體驗。
在實際的使用中,會遇到各種問題,大家可以自行去拓展,里面有很多的參數設置和功能,我這邊就不一一去說明,邊用邊學。