概觀
Laravel 的 Queue 功能提供了 Unique(去重) 與 Debounce 兩種 Job 執行控制。皆是為了「當同一 Job 被多次 dispatch 時,省去無謂執行」的機制,但運作有所不同。Unique Jobs — ShouldBeUnique
當同一 Job 存在於 Queue 期間,將忽略追加的 dispatch。
UpdateSearchIndex 已在 Queue 中(或正在處理),再次 dispatch 同一 Job 會被忽略。
以 key 限縮唯一性約束 — UniqueFor + uniqueId()
若相同 Job 類別下希望將「商品 A 的更新」與「商品 B 的更新」視為不同 Job,可使用 uniqueId() 方法定義 key。
uniqueId()回傳的值成為 cache lock 的 key。- 若指定
#[UniqueFor(秒數)],經過該秒數後 lock 會自動釋放(作為 Job 未被處理時的 fail-safe)。
指定 Cache Driver — uniqueVia()
若希望使用預設 cache driver 以外者,可實作 uniqueVia()。
Unique Jobs 需要支援 atomic lock 的 cache driver(
redis、database、memcached、dynamodb、file、array)。ShouldBeUnique vs ShouldBeUniqueUntilProcessing
ShouldBeUnique 的 lock 會保持至 Job 完成或達到重試上限。這在某些情境下會有問題。
例: Queue 中有 1 件 UpdateSearchIndex(product_id: 42),Worker 開始處理後想立即重新 dispatch 相同 Job。ShouldBeUnique 於處理完成前不會讓第 2 件進入 Queue。
此時可使用 ShouldBeUniqueUntilProcessing。因為 lock 於處理開始前釋放,故當 Worker 取出 Job 的瞬間即可進行下次 dispatch。
比較彙整
Debounced Jobs — #[DebounceFor]
DebounceFor attribute 為 Laravel 13 新增的功能。- 以
debounceId()回傳的值辨識 Job(每個 product ID 有獨立的 debounce)。 - 即便 30 秒內以相同
productIddispatch 10 次,也只執行最後 1 件。
maxWait — 最大等待時間上限
於頻繁更新的資料,debounce 可能持續而使 Job 永遠不執行。可透過 maxWait 設定最大延遲時間。
指定 Cache Driver — debounceVia()
JobDebounced 事件
被後續 dispatch 覆蓋的 Job 會發出 Illuminate\Queue\Events\JobDebounced 事件後從 Queue 中被刪除。透過監聽此事件可以追蹤及監視被 debounce 的 Job。
應該使用哪一個
內部實作
Unique Jobs 的 lock 機制
當ShouldBeUnique Job 被 dispatch 時,Laravel 內部會取得 cache 的 Atomic Lock。lock key 格式如下:
Debounced Jobs 的實作
DebounceFor 內部使用管理「Debounce 視窗」的 cache 項目。每次有新的 dispatch 進來時:
- 從 Queue 移除既有 Job(發出
JobDebounced事件) - 將新 Job 加入 Queue(附帶 Debounce 秒數的延遲)
- 重置 cache 的計時器
maxWait,也會記錄初次 dispatch 的時間戳記,防止超過該時刻起 maxWait 秒的 Debounce。