什么可能导致预定的Rails Active Jobs消失?

7
我怀疑我们的一些活动工作正在消失,但我不知道为什么。下面是我找到的一个证据它消失了,但不知道原因。
我们的网站使用外部云打印服务。我们启动作业,然后检查它们的状态。成功创建远程云打印后,我们创建一个主动作业立即检查其状态。如果已完成(无论成功与否),则将其标记为已完成。如果没有,则检查状态作业会创建另一个作业,并稍微延迟。延迟时间每次增加。
今天进行状态检查时,日志显示等待时间达到了128秒。但是下一个状态检查没有发生,而日志中也没有错误。
我们使用由delayed job支持的active job。下面是状态检查作业的代码。它看不到任何逻辑上的缺陷,这不会导致正确收集状态检查或等待的另一次尝试。
class CheckCloudPrintStatusJob < ApplicationJob
  queue_as :default

  def perform(cloud_print, count = 0)
    cloud_print.update_status

    unless cloud_print.finished?
      count += 1
      wait = 2**(count-1)

      if count > 15
        cloud_print.mark_as_failed

        puts "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
        puts "~~~~~~~~~~~~~~~~~~ Cloud printing ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
        puts "Cloud print ##{cloud_print.id} failed"
        puts "Finally waited #{wait} seconds and then cancelled."
        puts "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
      else
        puts "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
        puts "~~~~~~~~~~~~~~~~~~ Cloud printing ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
        puts "Checking status of cloud print ##{cloud_print.id}"
        puts "Waiting #{wait} seconds and then retrying."
        puts "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"

        CheckCloudPrintStatusJob.set(wait: wait.seconds).perform_later(cloud_print, count)
      end
    end
  end
end

update_status引发错误时会发生什么?您能分享一下update_status中的代码吗? - Edmund Lee
2个回答

3

正确,所述逻辑没有缺陷,这将导致正确收集的状态检查或等待的另一次尝试。

我已经验证了您的作业代码在以下设置中成功执行超过128秒的等待:

  • rails new 项目
  • delayed_job_active_record 添加到 Gemfile(运行 bundle install
  • rails generate delayed_job:active_recordrake db:migrate 安装 gem 并创建延迟作业 DB 表
  • config.active_job.queue_adapter = :delayed_jobconfig/application.rb
  • 基本的 CloudPrint < ApplicationRecord 模型,在 app/models/cloud_print.rb 中具有 update_statusfinished?mark_as_failed 方法
  • 提供的代码在 app/jobs/check_cloud_print_status_job.rb
  • 通过 Rails Console (bin/rails c) 运行 CheckCloudPrintStatusJob.perform_later(CloudPrint.create) 来排队作业

由于上述序列没有出现任何问题,您需要通过提供一个更完整且可验证的示例来扩展搜索,以实际复制该问题。一旦您能够持续复制问题,请将整个Rails项目上传到GitHub repo中,或者调查您环境和项目配置的其他方面。以下是一些可能性:

  • 您的模型类中可能会有逻辑错误导致引发异常;
  • 工作进程守护程序可能已中止或被杀死;
  • 作业队列可能已被清除(例如,通过rake jobs:clear);
  • 另一个进程可能已修改和/或删除正在处理的模型对象;
  • finished?在调用update_status后返回true,即使处理成功完成,也会导致最终状态检查未被打印。
注意 - Delayed Job 支持在失败的作业上使用延迟 5 秒 + N ** 4 进行重试,其中 N 是尝试次数,无需重新实现此逻辑。如果 cloud_print.finished? 为 false,则只需 raise 异常即可,不需要其他自定义延迟代码。
class CheckCloudPrintStatusJob < ApplicationJob
  queue_as :default

  def perform(cloud_print)
    raise 'Not ready' unless cloud_print.finished?
  end
end

感谢您提供全面的响应。虽然您的答案没有直接为我们解决问题,但它有助于让我们思考问题可能存在的其他地方。奇怪的是,解决方案似乎是(除了增加大量额外的安全性之外)从dj切换到sidekiq。显然这不应该有任何区别,但显然确实有。 - Simmo

0

从工作代码中可以看出,参数cloud_print是某个Ruby类的实例(似乎是ActiveRecord::Base)。一般来说,将复杂对象作为后台作业的参数并不是一个好主意,因为这些参数必须被序列化为字符串、JSON或YAML。DelayedJob使用YAML序列化对象,有时可能无法恢复模型实例。例如,如果延迟作业作为回调函数before_create运行-模型对象尚未保存,因此无法恢复。更多信息请参见https://github.com/collectiveidea/delayed_job/wiki/Common-problems#jobs-are-silently-removed-from-the-database


3
自 Rails 5 开始(至少),ActiveJob 在传递 ActiveModel 时使用 GlobalId,如此处所述 http://guides.rubyonrails.org/active_job_basics.html#globalid。这意味着我们可以传递一个 ActiceRecord 对象,并且它将存储类和 ID,而不是序列化对象的属性。我们仍然需要处理在事务中的 after_create 问题。 - tal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接