【发布时间】:2020-11-17 04:49:36
【问题描述】:
我有一个可调度的工作来清除和重建特定模型的缓存。
缓存重建大约需要 10 秒。
该作业有时会被顺序触发多次,我经常会遇到多个排队的作业,它们都为同一模型执行相同的缓存清除和重建。
我正在寻找一种在调度当前作业之前删除该特定模型的任何相同作业(缓存重建)的方法。
【问题讨论】:
-
你用什么做队列驱动?
-
我使用 Redis 驱动
我有一个可调度的工作来清除和重建特定模型的缓存。
缓存重建大约需要 10 秒。
该作业有时会被顺序触发多次,我经常会遇到多个排队的作业,它们都为同一模型执行相同的缓存清除和重建。
我正在寻找一种在调度当前作业之前删除该特定模型的任何相同作业(缓存重建)的方法。
【问题讨论】:
没有简单或 %100 的工作方式来删除重复的工作。 Laravel 的 Redis 队列驱动程序使用排序集和列表来处理延迟/非延迟作业。这个answer 可能会提供一些关于它的细节。当您将作业推送到队列中时,您无法在处理之前将其删除。 (你可以尝试,但很难,链接有答案)。
您可以做的是创建一个控制机制来防止触发缓存失效作业。假设在你推送你的工作之前,你设置了一个唯一的标识符。您可以将 Redis 的 SET 命令与 EX 和 NX 选项一起使用。
在你推送你的工作之前,你执行第一个命令是这样的;
127.0.0.1:6379> set mymodel:id:1 some-random-string-test EX 15 NX
OK
127.0.0.1:6379> ttl mymodel:id:1
(integer) 10
127.0.0.1:6379> get mymodel:id:1
"some-random-string-test"
127.0.0.1:6379> set mymodel:id:1 some-random-string-test-another EX 15 NX
(nil)
127.0.0.1:6379>
您正在做的是,您获得模型的id 并创建一个密钥。您使用 expire 和 set if not exists 选项设置您的密钥。如果响应是OK,那么您将在给定的时间间隔内(在我的示例中为 15 秒)首次设置此键。如果您收到nil 响应,这意味着给定ID 的工作仍然是locked。所以你不会发送它。它会为每个模型提供 15 秒的时间窗口,以防止您调度它。
--
如果您不能(不想)阻止作业被触发,那么您可以以不同的方式使用相同的命令。每当您要调度作业时,您都会创建一个唯一标识符并在调度它之前执行set mymodel:id:1 some-random-string-test EX 15 NX。但是这一次您也将向作业的构造函数发送标识符。在handle 方法的开头,您将使用redis 的GET 方法获取mymodel:id:1 的值,并将其与您发送给作业构造函数的标识符进行比较。 15 秒内只有 1 个匹配的标识符,这意味着只有一个作业将被“完全”处理。为相同作业创建的其他标识符不会更新该 redis 键(NX 选项)的值,因此其他作业的标识符将与 mymodel:id:1 的值不匹配。这意味着它们将被取消或未完全处理,因为它们不会通过条件。
【讨论】:
考虑在phpredis 连接上使用setnx 命令。
注意。这与php artisan queue:work 命令上的--tries 选项不同,并重试失败的作业 .
【讨论】:
尝试为每个作业使用不同的队列(例如:每个模型的队列),以便您可以检查队列大小
Queue::size('queue_name') 在分配新工作之前。
【讨论】: