如何使用 Laravel 的佇列機制?有哪些場景需要使用佇列 ?

surest發表於2021-12-03

入社群幾年了,好久沒有寫過一篇文章,正好今天蹭一下熱點,寫一下關於 如何使用 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;
}

設定失敗情況下重試次數

# 重試 5public $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 的用法還有很多,滿足自己的需求即可。

世界上沒有完美的解決方案,只有最適合你自己的方案,在工作中遇到問題,儘量要學會舉一反三,合理的運用各種 工具,設計方案去實現。
程式碼 只是最終一個縮影而已,最終的要學會理解,每個語言 每個框架,也只是一種方案的實現,融會貫通才無敵 …

Laravel 佇列文件

本作品採用《CC 協議》,轉載必須註明作者和本文連結
每天3小時...加油

相關文章