1

如果我调用以下内容:

return AdventureJob::dispatch($event->character->refresh(), $event->adventure, $event->levelsAtATime)->delay($timeTillFinished);

这将创建一个延迟 x 分钟的作业。我的工作都是通过redis处理的,有没有办法然后得到这个特定的工作或从队列中删除这个特定的工作?

人们谈论 php artisan 命令然后删除所有作业,这不是我想要的我想要获取有关此作业的某种信息(作业 ID?或队列 ID?Redis ID?)然后存储在数据库中,以便如果玩家然后取消冒险,我可以用它在队列中找到这个工作并删除它,假设它没有运行。

4

1 回答 1

2

没有直接或简单的方法可以做到这一点。延迟的作业保留在sorted sets待处理时间中score,作业负载保留为value.

有几种方法可以从排序集中删除元素(其中大多数需要一些努力,具体取决于延迟队列的大小),例如

  • 您获得已调度作业的“确切”有效负载,然后使用ZREM将其删除。这很难,因为对象(具有所有参数的作业的序列化版本)可能很大,并且您无法创建“精确”作业,因为它具有唯一标识符。您可以使用ZRANGEBYSCOREWITHSCORES. 它将为您提供带有分数的工作列表。您可以使用分数来识别要延迟的工作。获取值(序列化有效负载)然后使用ZREM.
  • 如果在特定时间只有一个作业要处理,您可以使用ZREMRANGEBYSCORE并使用已处理的时间。如果在那个时间正好有 n 个作业要处理,那么其他作业也可以被删除,因为ZREMRANGEBYSCORE需要时间间隔。
  • 您可以尝试使用ZSCAN扫描整个延迟列表(带有分页)并找到作业的分数和标识符,然后使用带有标识符的ZREMRANGEBYLEX将其删除。
  • 另一种方法可能是在方法的开头放置一个取消条件handle。这个需要应用层开发。每当您将作业推送到队列时,您都会向作业发送标识符,在 Redis 中也放入相同的标识符(您可以理解)(EXPIRE大于延迟时间)。当你想取消它时,然后从 Redis 中删除它。在 handle 方法中检查给定的标识符是否存在于 Redis 中,如果不存在则从代码块中提前返回。
于 2020-07-14T22:52:57.443 回答