在 Laravel 中取消作业
如果我调用以下内容:
return AdventureJob::dispatch($event->character->refresh(), $event->adventure, $event->levelsAtATime)->delay($timeTillFinished);
这将创建一个延迟 x 分钟的作业.我的作业都是通过redis处理的,有没有办法获取这个特定的作业或者从队列中删除这个特定的作业?
This will then create a job thats delayed x minutes. my jobs are all processed through redis, is there a way to then get this specific job or delete this specific job from the queue?
人们谈论 php artisan 命令然后删除所有作业,这不是我想要的我想获取有关此作业的某种信息(作业 ID?或队列 ID?Redis ID?)然后存储在数据库中如果玩家然后取消冒险,我可以使用它在队列中找到这个作业并删除它,假设它没有运行.
People talk about php artisan commands to then delete all jobs, thats not what I want I want to get some kind of information (Job ID? or queue ID? Redis ID?) about this job to then store in the database so that if the player then cancels the adventure, I can use that to find this job on the queue and delete it, assuming it's not running.
推荐答案
没有直接或简单的方法来做到这一点.延迟的作业保存在 sorted set
中作为待处理时间作为 score
和作业负载作为 value
.
There is no direct or easy way to do it. The delayed jobs are kept in sorted sets
as to-be-processed time as score
and job payload as the value
.
有几种方法可以从已排序的集合中移除元素(其中大多数需要一些努力,具体取决于延迟队列的大小),例如
There are several ways to remove an element from the sorted sets(most of them require some efforts depending on the size of the delayed queue) such as
- 你得到了精确的"分派作业的有效负载,然后使用 ZREM 将其删除.这很困难,因为对象(具有所有参数的作业的序列化版本)可能很大,而且您无法创建精确"的对象.工作,因为它有一个唯一的标识符.您可以使用 ZRANGEBYSCORE 和
WITHSCORES
获取它的列表.它将为您提供带有分数的工作列表.您可以使用分数来识别被延迟的工作.获取值(序列化的有效负载)然后使用ZREM
. - 如果在特定时间只有一项作业要处理,您可以使用 ZREMRANGEBYSCORE使用处理时间.如果恰好在那个时间有 n 个作业要处理,那么其他作业也可以删除,因为
ZREMRANGEBYSCORE
需要时间间隔. - 您可以尝试使用 ZSCAN 扫描整个延迟列表(带分页)并找到作业的分数和标识符,然后使用带有标识符的 ZREMRANGEBYLEX 将其删除.
- 另一种方法是在
handle
方法的开头放置一个取消条件.这个需要应用层开发.每当您将作业推送到队列时,您都会向作业发送一个标识符,在 Redis 中也放置相同的标识符(您可以理解)(EXPIRE
大于延迟时间).当你想取消它时,然后从Redis中删除它.在 handle 方法内部检查给定的标识符是否存在于 Redis 中,如果不存在则从代码块提前返回.
- You get the "exact" payload of the dispatched job and then use ZREM to remove it. It is hard because the object(serialized version of the job with all the parameters) can be huge and you can't create the "exact" job because it has a unique identifier. You can get the list of it with ZRANGEBYSCORE and with
WITHSCORES
. It will give you the list of jobs with their scores. You can use score to identify to be delayed job. Get the value(serialized payload) then useZREM
. - If there is only one job to be processed at a specific time you, may use ZREMRANGEBYSCORE with using the processed time. If there are n jobs to be processed exactly that time then other jobs can be deleted too since
ZREMRANGEBYSCORE
takes time interval. - You may try to use ZSCAN to scan the whole delayed list(with pagination) and find the score and identifier of the job, and then use ZREMRANGEBYLEX with the identifier to remove it.
- Another way could be putting a cancellation condition at the beginning of
handle
method. This one requires application layer development. Whenever you push a job to the queue you send an identifier to the job, put same identifier(that you can understand) in Redis too(withEXPIRE
greater than the delayed time). When you want to cancel it, then delete it from the Redis. Inside the handle method check whether the given identifier exists in Redis, if not early return from the code block.
相关文章