在 Laravel 中取消作业

Posted

技术标签:

【中文标题】在 Laravel 中取消作业【英文标题】:Cancel Jobs In Laravel 【发布时间】:2020-11-04 08:23:30 【问题描述】:

如果我调用以下代码:

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

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

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

【问题讨论】:

【参考方案1】:

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

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

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

【讨论】:

我接受了这一点,因为第四点是最简单的方法。 @TheWebs 是的,如果您有成千上万的工作等待处理,另一个也不能保证(也很难)。谢谢。 @TheWebs 你能解释一下你是如何在工作的handle 方法上处理它的吗?我需要防止 Redis 复制队列中的作业。

以上是关于在 Laravel 中取消作业的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 4 的 Cron 作业

Laravel 安排推送通知并在必要时取消它

PHP apcu 在 Laravel 排队/分派作业中不持久

在 laravel 调度程序中重新运行作业

从 Laravel 作业调用的 Laravel 命令

Laravel 队列 - 作业之间暂停