Laravel queue job 中 WithoutOverlapping 和 ShouldBeUnique 的区别
这两个很容易混淆,但它们解决的是完全不同层级的问题:
ShouldBeUnique = 防“重复入队”
WithoutOverlapping = 防“并发执行”
一、核心区别
| 机制 | 阶段 | 作用 |
|---|---|---|
ShouldBeUnique | 入队时 | 队列里只能有一个 |
WithoutOverlapping | 执行时 | 同一时间只能跑一个 |
二、ShouldBeUnique(唯一 Job)
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Contracts\Queue\ShouldBeUnique;
class MyJob implements ShouldQueue, ShouldBeUnique
{
public function uniqueId()
{
return 'user:1';
}
}
行为
dispatch(new MyJob()); // ✓ 入队
dispatch(new MyJob()); // ✕ 被忽略
队列里只会有一个
在 dispatch 时生效
用 cache 锁(Redis)
防止重复任务堆积
适用场景
防止重复提交任务
同一用户只允许一个任务
三、WithoutOverlapping(执行互斥)
use Illuminate\Queue\Middleware\WithoutOverlapping;
public function middleware()
{
return [
new WithoutOverlapping('user:1')
];
}
行为
Job1 开始执行
Job2 来了 → 等待 or 释放(取决配置)
队列里可以有多个,但不会同时执行
在 handle 执行时生效
基于 mutex lock 控制并发
可选配置
(new WithoutOverlapping('key'))->releaseAfter(10);拿不到锁 → 10 秒后重试
四、最直观对比(重要)
没有控制
用户点 10 次按钮 → 10 个 Job
→ 全部执行 ✕
ShouldBeUnique
只进队列 1 个 ✓
WithoutOverlapping
进队列 10 个 ✓
但一次只执行 1 个 ✓
五、组合使用
class MyJob implements ShouldQueue, ShouldBeUnique
{
public function uniqueId()
{
return 'user:1';
}
public function middleware()
{
return [
new WithoutOverlapping('user:1')
];
}
}
效果
1. 防止重复入队
2. 防止并发执行
双保险 🔥
六、常见坑
1. ShouldBeUnique 会“悄悄失败”
dispatch(new MyJob());
dispatch(new MyJob());
第二个:
不会报错,只是 silently ignore ✕
2. WithoutOverlapping 需要 Redis
否则锁不可靠
3. uniqueId 不写 = 全局唯一
return 'fixed-key';
所有 Job 都被挡住 ✕
七、一句话总结
ShouldBeUnique:
不让重复进队列
WithoutOverlapping:
不让同时执行