delayed_job 需要注意的几个地方( advanced usage of delayed_job )
访问量: 3580
delayed_job是非常强大的工具。但是,它也有它适应的场合。用的好的话,非常给力。用的不好的话,就麻烦了。 ( delayed_job is a good tool, but we should be clear how it should be used)
适合的场合:
1. 有很多任务需要处理,这些任务可以延迟一段时间完成,例如:发送1W个EMAIL。 更新10W个设备的信息。等。
2. 各个任务之间没有复杂的联系,哪个先来,哪个后来,没有固定的需求。
3. (最好不要出现这个情况)有的话也可以,但是一定要简单! 例如: 100个任务中,前50个优先级高,先执行。
不适合的场合:( un-fitted scenario: the tasks should be run in a complicated sequence with different priorities)
1. 有严格的优先级(有复杂的先后顺序)
这几天在项目中有非常深刻的体会:
1. delayed_job 属于并发执行,所以冒出来很多意想不到的问题。
2. delayed_job 使用了独立于rails的脚本执行(script/delayed_job start) 所以无法使用单元测试。 难于测试,就难于开发。
3. 不是按照我想象的严格遵守优先级。 例如: 10 个worker, 遇到5个任务:
job1: priority = 0
job2: priority = 0
job3: priority = 10
job4: priority = 20
job5: priority = 30
尽管它们的优先级不同,但是,由于有 10 个worker在待命,所以, 这5个job会被同时执行。T.T
4. 要解决这个问题,我使用了 wait_job.rb 但是效果极差。大家不要参考了。
1 # a job just for waiting the preconditional jobs (higher priority jobs) done 2 class WaitUntilPreconditionalsDoneJob < Struct.new(:priority) 3 include DelayedJobPriority 4 def perform 5 wait_until_higher_priority_jobs_done(priority) 6 end 7 end
接上文,要解决这个问题,只能使用 before/after hooks. 例如:
1 # usage: 2 # Delayed::Job.enqueue(UpdateRemoteConflictingDeviceInfoJob.new(), 10) 3 class UpdateRemoteConflictingDeviceInfoJob < Struct.new(:device_group, :cloudset) 4 def before(job) 5 Rails.logger.info '=== before UpdateRemoteConflictingDeviceInfoJob' 6 end 7 def perform 8 device_group.update_the_remote_conflicting_devices(cloudset) 9 end 10 11 def after(job) 12 Rails.logger.info '=== in after hook, now starts UpdateLocalEmailsByRemoteValueJob' 13 Delayed::Job.enqueue(UpdateLocalEmailsByRemoteValueJob.new(device_group), :priority => 20) 14 end