Skip to main content

什麼是 Queue

在 Web 應用程式中,會有寄信、縮圖、對外部 API 查詢等需要數秒才能完成的處理。 若在 HTTP 請求中同步進行這些處理,使用者必須一直等到回應返回。 使用 Laravel 的 Queue,能將這些重負載處理在背景以非同步方式執行。 請求會立刻回應,實際處理由 worker process 另外執行。
Queue 支援資料庫、Redis、Amazon SQS 等多種後端。 開發環境使用 sync driver 時,不透過 queue 即可立即執行 job。

Queue 的設定

config/queue.php

Queue 的設定集中於 config/queue.php。 以 QUEUE_CONNECTION 環境變數切換所使用的 driver。

.env 設定

資料庫 driver 的準備

使用 database driver 時,需要儲存 job 的資料表。 Laravel 11 以後的新專案已預設包含 migration, 若沒有,可用以下指令建立:

Redis driver 的準備

使用 redis driver 時,於 config/database.php 加入 Redis 連線設定, 並以 Composer 安裝 driver:

SQS Overflow Storage

Amazon SQS 的訊息 payload 有大小上限。 若要處理較大的 payload,可加入將超過的部分存到 cache store、只將 pointer 傳給 SQS 的設定。
  • 啟用 enabled 時,會將大於 1MB 的 payload 存到指定的 cache store。
  • always 設為 true,則無論大小都會把所有 SQS payload 存到 cache store。
  • delete_after_processing 會在 job 成功後刪除已儲存的 payload(預設 true)。
  • flush_on_clear 設為 true,執行 queue:clear 時會 flush overflow 用的 store。因會避免清掉一般 cache,建議搭配專用 store 使用。

建立 Job 類別

make:job 指令

make:job Artisan 指令產生 job 類別的樣板:
會產生 app/Jobs/SendWelcomeEmail.php

Job 類別的結構

實作 ShouldQueue 介面,是在告訴 Laravel 這個 job 要以 queue 非同步處理。 Queueable trait 提供 job 佇列操作所需的方法。
在建構子傳入 Eloquent model 時,Laravel 會自動只序列化 ID。 執行時會再從資料庫重新取得最新資料,因此 queue 的 payload 較輕。

Job 的分派

dispatch()

從 controller 或 service 將 job 送到 queue,使用 dispatch()

延遲 dispatch

delay() 方法可讓 job 的執行延後指定時間。

dispatchAfterResponse()

使用 dispatchAfterResponse() 會在回應 HTTP 給使用者之後立即執行 job。 在 sync driver 下也能運作,適合不需要專用 worker 的輕量用途。

分派到特定 queue

Queue Routing

若要將特定 job 類別預設導向指定 connection/queue,可在 ServiceProvider 的 boot() 中使用 Queue::route()。無需為每個 job 類別加上 onQueue() / onConnection(),可集中管理。
也可以指定介面、trait、父類別。所有實作、使用、繼承這些的 job 都會自動套用。 若要一次路由多個 job,傳入陣列:
Queue Routing 可被 job 端的 onQueue() / onConnection() 覆寫。

同步執行(用於測試/開發)

使用 dispatchSync() 會跳過 queue 立即執行。

大量 dispatch

當要一次分派多個獨立的 job 時,可使用 Bus facade 的 bulk() 方法。適合不需要如 batch 處理般的追蹤或 callback 的情境。 Bus::bulk() 會依所設定的 queue connection 與 queue 名稱將 job 分組,並將每組整批推入 queue,因此效率較高。
Bus::bulk() 會將 job 以批次方式送入 queue。與 batch 處理(Bus::batch())不同,不提供進度追蹤或完成 callback。適合需要簡潔地批次送出大量獨立 job 的情境。

Job 的處理

queue:work 指令

啟動 queue worker 來處理 job。
也可指定 driver 或 queue。
queue:work 啟動後會持續運行。變更程式碼時請以 queue:restart 重啟 worker。 正式環境一般會以 Supervisor 等 process manager 管理。

Queue Worker 的監控選項

可組合常用選項精細控制 worker:

在 Job 類別中設定重試

比起命令列選項,將設定寫在 job 類別本身有時更易於管理。

Job 的 Release(Release middleware)

當在特定條件下想不執行 job 而放回 queue 時,使用 Release middleware 可簡潔實作。
Release::unless() 會在條件為 false 時 release。
使用 closure 可寫更複雜的條件:
即使 release job,嘗試次數仍會累加。請適當設定 #[Tries]$tries 屬性。

失敗 Job 的處理

準備 failed_jobs 資料表

當 job 超過最大嘗試次數,會記錄到 failed_jobs 資料表。 若沒有此表,可用以下指令建立:

失敗時的收尾

在 job 定義 failed() 方法,可撰寫失敗時的收尾處理。

依例外停止重試

有些例外類型希望不再重試而直接視為失敗。在 bootstrap/app.phpwithExceptions() 中以 dontRetry 指定要對應的例外類別。
若需更細緻的控制,可將 closure 傳給 dontRetryWhen。當 closure 回傳 true,job 會立即標記為失敗、不再重試。
對於像驗證錯誤或付款失敗(訂閱到期等)這類重試也不會改變結果的例外,用此方式立即失敗會更有效率。

檢視失敗 job 清單

重試失敗 job

刪除失敗 job

常用的 queue driver

database driver

無需額外的中介軟體即可使用的簡單 driver。 會將 job 存到 jobs 資料表,由 worker 輪詢並處理。
  • 優點:安裝簡單,可直接沿用既有 RDBMS
  • 缺點:對資料庫負擔大,不適合大量 job

redis driver

在正式環境中最常使用的高速 driver。 以記憶體運作,吞吐量高於資料庫,可處理大量 job。
  • 優點:高速、可擴展
  • 缺點:需要準備 Redis 伺服器
若在正式環境運行 Redis queue,可考慮導入 Laravel Horizon。 可在漂亮的儀表板即時監控 job 狀況。

以 Supervisor 進行正式運行

在正式環境中,需要一種當 queue:work process 因某原因停止時能自動重啟的機制。 Linux 環境中一般使用 Supervisor
numprocs=2 平行啟動 2 個 worker process。 設定後重新載入 Supervisor:

實務範例:以 queue 處理寄信

1

建立 job 類別

2

實作 job 的處理

3

從 controller 分派

4

啟動 worker

總結

  • 寄送 email/SMS
  • 圖片、影片的縮圖或格式轉換
  • 向外部 API 送出請求
  • 產生報表或 CSV 匯出
  • Webhook 的送出
.env 設為 QUEUE_CONNECTION=sync,job 就會不經過 queue 立即執行。 不用啟動 worker 就能確認運作,開發中很方便。
最後修改於 2026年8月2日