Back

delayed_job 需要注意的几个地方( advanced usage of delayed_job )

发布时间: 2012-08-12 22:43:00

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   

Back