Rails ActiveJob - 如何阻止作业在 before_enqueue 中排队

Posted

技术标签:

【中文标题】Rails ActiveJob - 如何阻止作业在 before_enqueue 中排队【英文标题】:Rails ActiveJob - how to stop job from being enqueued in before_enqueue 【发布时间】:2017-09-10 20:54:54 【问题描述】:

我正在运行 Rails 4.2.8,我想让我的工作只在特定条件下运行。目前我正在检查调用作业的代码,但在作业类中包含逻辑会更清晰。有没有人这样做过?

class MyJob < ApplicationJob
  before_enqueue do |job|
    # check and stop job from being enqueued under certain conditions
  end
  def perform(args*)
    # code here
  end
end

我使用 Sidekiq 4.2.10 作为后台作业适配器。

【问题讨论】:

【参考方案1】:

throw :abort 从您的before_enqueue 停止执行回调链和perform

代码:https://github.com/rails/rails/blob/fc20050ea69ba3b8d8bc90171d2dcbf93e9a1dae/activesupport/lib/active_support/callbacks.rb#L23

【讨论】:

我尝试在before_enqueue 中引发异常并使用discard_on,但没有成功。异常没有被捕获,它正在停止代码的执行。所以你的解决方案不起作用@Sergio。如果在 before_perform 回调中引发异常,则引发异常和丢弃将起作用。可能是因为 before_enqueue 是在将作业入队的同一进程中运行的,但 before_perform 是在 sidekiq worker 中运行的。 Rails 存储库中的测试似乎表明 throw-ing 和 exception (不要在 Ruby 中与 raise-ing 和 error 混淆):abort 它将停止工作的排队。 github.com/rails/rails/blob/… @Adeynack :abort 也不例外 @SergioTulentsev:用 Ruby 术语来说是这样。例外是符号。见coderwall.com/p/lhkkug/… @Adeynack:是的,听起来更像。 :+1:【参考方案2】:

您可以使用around_enqueue 来获得相同的结果而不会引发异常。当您的工作期望不排队时,这可能很有用。

例如:

around_enqueue do |_job, block|
   if my_condition 
      block.call # this will enqueue your job
   end
end

OBS:值得注意的是,此答​​案基于 Rails 5 ActiveJob 代码,但也必须适用于 Rails 4。

【讨论】:

我认为使用 around_enqueue 是在将作业添加到队列之前取消作业的唯一选项。我尝试将 before_enqueue 与 discard_on 结合使用,但没有奏效。未捕获异常,它正在停止执行正在排队作业的进程中的代码。

以上是关于Rails ActiveJob - 如何阻止作业在 before_enqueue 中排队的主要内容,如果未能解决你的问题,请参考以下文章

Rails 4.2 从活动作业中获取延迟的作业 ID

如何将自定义的延迟作业作业与 ActiveJob 一起使用?

我应该在生产中使用 rails5 ActiveJob 默认异步适配器来进行小型后台作业吗?

集成测试ActionMailer和ActiveJob

在 Rails 中安排一个 ActiveJob

SerializationError Rails ActiveJob 时间和日期