简体   繁体   English

如何确保相同的延迟作业不会同时两次(互斥)

[英]How can I make sure that the same delayed job does not twice at the same time (mutually exclusive)

For a project I want to make sure that there a certain job is not running twice at the same time.对于一个项目,我想确保某个作业不会同时运行两次。 This job is an importer and just does not make sense to run again if it is still running.此作业是一个导入程序,如果它仍在运行,则再次运行是没有意义的。 If we detect that the job is already running, I want to raise an exception so I get alerted about long running jobs.如果我们检测到作业已经在运行,我想引发异常,以便我收到有关长时间运行的作业的警报。

I found a way to solve this.我找到了解决这个问题的方法。 We introduce a new custom job .我们引入了一个新的自定义作业 When the job is performed, we check if there is already another job running:执行作业时,我们检查是否已经有另一个作业在运行:

# checks if the job is already running when it is supposed to be performed.
# if it is already running, then we raise an error
# jobs with different arguments but same object and method raise an error.
class ExclusiveJob < Struct.new(:object, :meth, :args)
  class ExclusiveJobError < RuntimeError; end

  def initialize(object, meth, *args)
    super(object, meth, args)
  end

  def perform
    same_and_current_jobs = Delayed::Job
      .where(last_error: nil)
      .where.not(locked_at: nil)
      .collect { |job| YAML.load(job.handler) }
      .select { |handler| handler.is_a?(self.class) && handler.object == object && handler.meth == meth }
    
    raise ExclusiveJobError, "Tried to perform \"#{identifier}\", but it is already running" if same_and_current_jobs.count > 1 # we have more than this job in the pipeline

    object.send(meth, *args)
  end

  protected

  # just for display purposes
  def identifier
    "#{object}##{meth}"
  end
end

Please mind that this code is not ideal because we are relying on the internal data model of delayed job (however it is officially documented ).请注意,这段代码并不理想,因为我们依赖于延迟作业的内部数据模型(但它有官方文档)。 Also, please mind that this class does not take method arguments into account, ie we skip the job if another job with the same receiver & method is found.另外,请注意该类不考虑方法参数,即如果找到具有相同接收器和方法的另一个作业,我们将跳过该作业。 And, we are not using ActiveJob, there are probably ways to solve this using callbacks .而且,我们没有使用 ActiveJob,可能有使用回调解决这个问题的方法。

To enqueue such an exclusive job:排入这样一个排他性的工作:

Delayed::Job.enqueue ExclusiveJob.new(MySuperService, :run, 'arg1', :arg2)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM