如何解决如何确保同一份延迟的工作不会同时发生两次互斥
对于一个项目,我想确保某个作业没有同时运行两次。这项工作是进口商,如果仍在运行,则没有必要再次运行。如果我们检测到该作业已经在运行,则我想引发一个异常,以便使我收到有关长时间运行的作业的警报。
解决方法
我找到了解决此问题的方法。我们引入了一个新的custom job。执行作业后,我们检查是否已经有另一个作业正在运行:
# 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,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
请注意,此代码不是理想的代码,因为我们依赖延迟工作的内部数据模型(但是officially documented)。 另外,请注意,此类不会考虑方法参数,也就是说,如果找到另一个具有相同接收方和方法的作业,我们将跳过该作业。 而且,我们不使用ActiveJob,可能有使用callbacks解决此问题的方法。
要加入这样的独家工作:
Delayed::Job.enqueue ExclusiveJob.new(MySuperService,:run,'arg1',:arg2)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。