入社群幾年了,好久沒有寫過一篇文章,正好今天蹭一下熱點,寫一下關於 如何使用 Laravel 的佇列機制?有哪些場景需要使用佇列
的我的理解
首先,我們要知道為什麼要使用佇列,不使用佇列會怎麼樣!優缺點如何
我們可以舉例 幾個簡單場景。
郵件傳送
郵件傳送一般會面臨哪些問題 ??
- 傳送緩慢
- 傳送失敗
- 傳送頻率過高,被服務商拒絕 又或者 被進入垃圾箱
使用佇列的好處在與哪裡
提高客戶端響應
當傳送時,我們不要立即處理,而是丟給伺服器,且佇列進行管理和排程。 你可以自定義選擇立即傳送 或者 根據配置延遲傳送
提高容錯能力
在傳送過程中,或許我們可能會遇到,目標被拒絕。例如大多數人 會遇到給
admin@qq.comn
傳送報錯 502 的場景。
那這種場景,那麼這種場景,我們可以理解其為是一個事件,在郵件傳送的過程中,我們可以 引發構建出如下幾種事件傳送失敗
郵件記錄入庫
程式碼異常
郵件傳送成功回撥
傳送失敗重試
通過此郵件傳送,可能會導致多個耗時任務的產生,那我們其實也可以構建出多個 佇列服務 出來。每個佇列管理 自己的事情,很好的 解耦 他們
通過 Laravel 佇列 可以很好的進行設定 立即傳送、延遲傳送、重試傳送
傳送頻率可控
使用過批量傳送的郵件的 開發者 必然會遇到一個問題,那便是,如果我們直接進行批量傳送,即同一時間 進行大量的郵件傳送。那麼郵件服務商很可能會把我們的郵件給拒絕 或者 郵件進入垃圾箱,被識別為 廣告
那麼,這裡便是用到了 延遲傳送,我們可以根據當前佇列服務中,已知的 正在等待 投遞的郵件,合理的配置頻率,或者 切換郵件配置,來達到,頻率可控。如設定 一個配置一分鐘之類傳送10次,等等方案。
同樣,我們這裡可以做到 配置、頻率控制、傳送控制 解耦
其他
當然 我們還有很多種情況都會用到
- 伺服器端下載 excel
- 伺服器端非同步多工處理 大資料
- 錯誤訊息處理
如何使用 Laravel 佇列
這裡只是列出,大概的使用方向,和如何更好的去使用。程式碼可能跑不起起來,主要是理解 邏輯
我們這裡 使用的是 Redis 作為驅動
驅動設定為 Redis
> .env
QUEUE_CONNECTION=redis
> 在 config/queue.php 中可以找到
快速建立佇列 和 投遞任務
# 建立 任務
php artisan make:job ProcessPodcast
自動生成 app/Jobs/EmailJob.php
class EmailJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $data;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct(array $data)
{
$this->data = $data;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
$service = new EmailService();
// ... 檢查當前可用 Mailer
// 這裡你自定義就好了,這個方法中你可以根據你自己的配置,獲取到當前可用的配置
$mailer = $service->getMailer();
// ... 獲取當前要傳送的資料
$data = $this->data;
$service->send($mailer, $data);
}
}
這些操作都能從 文件中找到
呼叫 傳送
# 延遲 2分鐘 傳送
# 這裡使用的是 Crontab 包 (不過 Laravel 自帶)
EmailJob::dispatch()->delay(now()->addMinutes(2));
# 立即傳送 (不會進入到佇列中)
EmailJob::dispatchNow();
這裡的佇列預設用的 是 defult 佇列,我們可以修改為指定佇列服務
public function __construct(array $data)
{
# 使用 emailQueue
$this->onQueue('emailQueue');
$this->data = $data;
}
設定失敗情況下重試次數
# 重試 5 次
public $tries = 5;
設定超時時間
/**
* 確定任務應該超時的時間
*
* @return \DateTime
*/
public function retryUntil()
{
return now()->addMinutes(10);
}
啟動我們的佇列
如果不配置 onQueue 的話,可以不帶 —queue 引數配置
php artisan queue:work --queue=emailQueue
Laravel Event 也是通過 佇列實現的
# 建立 Event
php artisan make:event FailEvent
class FailEvent
{
use Dispatchable, InteractsWithSockets, SerializesModels;
protected $data;
protected $tag;
/**
* @param array $data 投遞的資料
* @param string $tag 要操作的事情
*/
public function __construct(array $data, string $tag = 'system')
{
$this->data = $data;
$this->tag = $tag;
}
}
# 建立 listener
php artisan make:listener FailListener
class FailListener
{
/**
* Handle the event.
*
* @param object $event
* @return void
*/
public function handle(FailEvent $event)
{
$this->{$event->tag}($event->data);
}
/**
* 處理系統異常
* DateTime: 2021/12/3 11:02 上午
* @param array $data
*/
public function system(array $data)
{
}
/**
* 處理郵件異常
* DateTime: 2021/12/3 11:02 上午
*/
public function email()
{
}
}
# app/Providers/EventServiceProvider.php
protected $listen = [
FailEvent::class => [
FailListener::class,
],
]
# 投遞
event(new FailEvent(['error' = '異常資訊'], 'email'));
其實,Laravel 大多數幫我實現了整個流程而已。可以嘗試自己使用 redis 來實現一個可控佇列。熟練是掌握 Redis 相關資料型別即可.
這裡簡要列出 Redis 中,在以上模式中會用到的資料型別
List
使用 它可以完成 出棧 入棧的 佇列功能
Hash
使用他 可以用來儲存,序列化後的 Event 或者 Job __construct 傳入進去的資料,儘量不要將整個 類 序列化進去
也可以實現儲存,Mailer 資料
Sorted Set
可以 設定時間為 Sorted Set 中的分數,通過分數排序,找到我們最近要執行的佇列任務
當然,Redis 的用法還有很多,滿足自己的需求即可。
世界上沒有完美的解決方案,只有最適合你自己的方案,在工作中遇到問題,儘量要學會舉一反三,合理的運用各種 工具,設計方案去實現。
程式碼 只是最終一個縮影而已,最終的要學會理解,每個語言 每個框架,也只是一種方案的實現,融會貫通才無敵 …
本作品採用《CC 協議》,轉載必須註明作者和本文連結