【问题标题】:Exact order of job execution for Rails delayed_jobRails delay_job 的作业执行的确切顺序
【发布时间】:2011-09-01 09:22:42
【问题描述】:

我正在使用collectiveide 的delayed_job 版本:https://github.com/collectiveidea/delayed_job

谁能指出当工人去选择下一份工作时使用的实际标准?我假设它类似于“SELECT id FROM delayed_jobs WHERE run_at > NOW() ORDER BY priority ASC, run_at ASC LIMIT 1”(首先按优先级选择,run_at time second),但我无法准确找到是什么经过考虑的。我已经在 GitHub 上的代码中进行了一些探索,但还没有找到下一份工作的实际查询。对一些事情感到好奇,包括“created_at”、“attempts”或“failed_at”是否会影响优先级。 (而且我意识到我不太可能找到实际的 SQL,这只是一种简单的方式来表示我假设查询所做的事情)。

其次,这个 gem 的实际文档有什么好的来源吗?对于在 Rails 中如此常用的东西,我看到的文档非常稀少。

【问题讨论】:

    标签: ruby-on-rails delayed-job


    【解决方案1】:

    在 backend/active_record.rb 中对源代码进行了一些挖掘:

        scope :ready_to_run, lambda {|worker_name, max_run_time|
          where(['(run_at <= ? AND (locked_at IS NULL OR locked_at < ?) OR locked_by = ?) AND failed_at IS NULL', db_time_now, db_time_now - max_run_time, worker_name])
        }
        scope :by_priority, order('priority ASC, run_at ASC')
    
        # Find a few candidate jobs to run (in case some immediately get locked by others).
        def self.find_available(worker_name, limit = 5, max_run_time = Worker.max_run_time)
          scope = self.ready_to_run(worker_name, max_run_time)
          scope = scope.scoped(:conditions => ['priority >= ?', Worker.min_priority]) if Worker.min_priority
          scope = scope.scoped(:conditions => ['priority <= ?', Worker.max_priority]) if Worker.max_priority
    
          ::ActiveRecord::Base.silence do
            scope.by_priority.all(:limit => limit)
          end
        end
    

    另外,backend/base.rb 中的这个位也很有趣:

        def reserve(worker, max_run_time = Worker.max_run_time)
          # We get up to 5 jobs from the db. In case we cannot get exclusive access to a job we try the next.
          # this leads to a more even distribution of jobs across the worker processes
          find_available(worker.name, 5, max_run_time).detect do |job|
            job.lock_exclusively!(max_run_time, worker.name)
          end
        end
    

    reserve 被工作人员调用以选择下一个工作。

    【讨论】:

    • 谢谢,非常有用。有趣的是,它使用 'failed_at' 列来确定不再尝试,而不是尝试次数
    • 当然,这确实具有有用的效果,您可以通过简单地清除 failed_at 字段而不是增加最大尝试配置或清除/减少记录的尝试来强制“失败”作业再次运行那份工作。
    • 可能还有更多。猜测一下,failed_at 可能不会设置,直到该作业尝试了最大次数。如果以这种方式配置,delayed_job 应该会重试作业。
    • 是的,你说得对,亚历克斯。 failed_at 保持为 NULL,直到达到最大尝试次数。由于配置问题,我尝试了许多作业,并且尝试了 25 次(默认最大值)。简单地设置 failed_at=NULL 会导致它们被尝试第 26 次,而无需增加配置的最大尝试次数。
    • fwiw,ActiveRecord 支持已被排除在 Delayed::Job 之外,现在可以在 github.com/collectiveidea/delayed_job_active_record 中找到 - 这解释了为什么我找不到 find_available 的定义 :)。
    【解决方案2】:
    delayed_job/lib/delayed/backend/active_record.rb
    

    self.find_available 致电ready_to_run 然后根据当前工作人员的最小/最大优先级对其进行范围 然后通过priority ASC, run_at ASC订购它

    scope :ready_to_run 来电

    where(['(run_at <= ? AND (locked_at IS NULL OR locked_at < ?) OR locked_by = ?) AND failed_at IS NULL', db_time_now, db_time_now - max_run_time, worker_name])
    

    所以它会生成类似的东西

    SELECT * FROM jobs where run at <= ? AND locked_at IS NULL OR locked_at < ?) OR locked_by = ?) AND failed_at IS NULL AND priority >= ? AND priority <= ? ORDER BY priority ASC, run_at ASC
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-19
      • 2019-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多