什么可能导致计划的 Rails 个活动作业消失?
What might cause scheduled Rails Active Jobs to disappear?
我怀疑我们的一些活跃工作正在消失,但我不知道为什么。下面是我找到的消失的证据,但不是原因。
我们的网站使用外部云打印服务。我们开始工作,然后检查他们的状态。成功创建远程云打印后,我们创建一个活动作业以立即检查状态。如果它完成(成功或失败),它被标记为这样。如果不是,则检查状态作业会创建另一个作业,但会稍有延迟。延迟每次都会增加。
今天进行一次状态检查,日志显示等待时间达到 128 秒。但是接下来的状态检查并没有发生,日志中也没有错误。
我们使用由延迟作业支持的活动作业。状态检查作业的代码如下。它看不到逻辑中的任何缺陷,这些缺陷不会导致正确收集的状态检查或另一次等待尝试。
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
正如工作代码所暗示的那样,参数 cloud_print
是某些 Ruby class 的实例(似乎 ActiveRecord::Base)。将复杂的对象作为后台作业的参数通常不是一个好主意,因为这些参数必须序列化为字符串、json 或 yaml。 DelayedJob 使用 YAML-serialized 个对象,有时可能无法恢复模型实例。例如,如果延迟作业作为回调运行 before_create
- 模型对象尚未保存且无法恢复。可以在此处找到更多信息 https://github.com/collectiveidea/delayed_job/wiki/Common-problems#jobs-are-silently-removed-from-the-database
正确,所述逻辑中没有缺陷会导致正确收集状态检查或再次尝试等待。
我已验证您的作业代码在 128 秒的等待后仍能通过以下设置成功运行:
rails new
项目
delayed_job_active_record
添加到 Gemfile
(运行 bundle install
)
rails generate delayed_job:active_record
和 rake db:migrate
安装 gem 并创建延迟作业数据库 table
config.active_job.queue_adapter = :delayed_job
在 config/application.rb
- 一个基本的
CloudPrint < ApplicationRecord
模型,在 app/models/cloud_print.rb
中具有 update_status
、finished?
和 mark_as_failed
方法
app/jobs/check_cloud_print_status_job.rb
中提供的代码
- 通过 Rails 控制台 运行
CheckCloudPrintStatusJob.perform_later(CloudPrint.create)
排队作业 (bin/rails c
)
由于上述序列运行正常,没有任何问题,您需要通过提供更多 complete and verifiable example 来实际重现问题来扩展您的搜索。一旦您能够一致地重现您的问题,或者调查您的环境和项目配置的其他方面,要么将您的整个 Rails 项目上传到 GitHub 存储库。这里有一些可能性:
- 您的模型 class 中可能存在可能引发任何异常的逻辑;
- worker-processing 守护程序可能已被中止或终止;
- 作业队列可能已被清除(例如,通过
rake jobs:clear
)
- 另一个进程可能修改了and/or删除了正在处理的模型对象;
finished?
可能在调用 update_status
后返回 true
,导致即使处理成功完成,最终状态检查也未打印。
N.B。 - Delayed Job 支持以 5 seconds + N ** 4
的延迟重试失败的作业,其中 N
是尝试的次数,不需要自己 re-implement 这个逻辑。如果 cloud_print.finished?
为假,只是 raise
一个例外,您不需要任何其他自定义延迟代码:
class CheckCloudPrintStatusJob < ApplicationJob
queue_as :default
def perform(cloud_print)
raise 'Not ready' unless cloud_print.finished?
end
end
我怀疑我们的一些活跃工作正在消失,但我不知道为什么。下面是我找到的消失的证据,但不是原因。
我们的网站使用外部云打印服务。我们开始工作,然后检查他们的状态。成功创建远程云打印后,我们创建一个活动作业以立即检查状态。如果它完成(成功或失败),它被标记为这样。如果不是,则检查状态作业会创建另一个作业,但会稍有延迟。延迟每次都会增加。
今天进行一次状态检查,日志显示等待时间达到 128 秒。但是接下来的状态检查并没有发生,日志中也没有错误。
我们使用由延迟作业支持的活动作业。状态检查作业的代码如下。它看不到逻辑中的任何缺陷,这些缺陷不会导致正确收集的状态检查或另一次等待尝试。
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
正如工作代码所暗示的那样,参数 cloud_print
是某些 Ruby class 的实例(似乎 ActiveRecord::Base)。将复杂的对象作为后台作业的参数通常不是一个好主意,因为这些参数必须序列化为字符串、json 或 yaml。 DelayedJob 使用 YAML-serialized 个对象,有时可能无法恢复模型实例。例如,如果延迟作业作为回调运行 before_create
- 模型对象尚未保存且无法恢复。可以在此处找到更多信息 https://github.com/collectiveidea/delayed_job/wiki/Common-problems#jobs-are-silently-removed-from-the-database
正确,所述逻辑中没有缺陷会导致正确收集状态检查或再次尝试等待。
我已验证您的作业代码在 128 秒的等待后仍能通过以下设置成功运行:
rails new
项目delayed_job_active_record
添加到Gemfile
(运行bundle install
)rails generate delayed_job:active_record
和rake db:migrate
安装 gem 并创建延迟作业数据库 tableconfig.active_job.queue_adapter = :delayed_job
在config/application.rb
- 一个基本的
CloudPrint < ApplicationRecord
模型,在app/models/cloud_print.rb
中具有 app/jobs/check_cloud_print_status_job.rb
中提供的代码
- 通过 Rails 控制台 运行
CheckCloudPrintStatusJob.perform_later(CloudPrint.create)
排队作业 (bin/rails c
)
update_status
、finished?
和 mark_as_failed
方法
由于上述序列运行正常,没有任何问题,您需要通过提供更多 complete and verifiable example 来实际重现问题来扩展您的搜索。一旦您能够一致地重现您的问题,或者调查您的环境和项目配置的其他方面,要么将您的整个 Rails 项目上传到 GitHub 存储库。这里有一些可能性:
- 您的模型 class 中可能存在可能引发任何异常的逻辑;
- worker-processing 守护程序可能已被中止或终止;
- 作业队列可能已被清除(例如,通过
rake jobs:clear
) - 另一个进程可能修改了and/or删除了正在处理的模型对象;
finished?
可能在调用update_status
后返回true
,导致即使处理成功完成,最终状态检查也未打印。
N.B。 - Delayed Job 支持以 5 seconds + N ** 4
的延迟重试失败的作业,其中 N
是尝试的次数,不需要自己 re-implement 这个逻辑。如果 cloud_print.finished?
为假,只是 raise
一个例外,您不需要任何其他自定义延迟代码:
class CheckCloudPrintStatusJob < ApplicationJob
queue_as :default
def perform(cloud_print)
raise 'Not ready' unless cloud_print.finished?
end
end