将Block传递给delayed_job

12

我有一个函数被标记为由延迟作业异步处理:

class CapJobs
  def execute(params, id)
    begin
      unless Rails.env == "test"
        Capistrano::CLI.parse(params).execute!
      end
    rescue
      site = Site.find(id)
      site.records.create!(:date => DateTime.now, :action => "Task Failure: #{params[0]}", :type => :failure)    
      site.save
    ensure
      yield id
    end 
  end   
  handle_asynchronously :execute
end 

当我运行这个函数时,我会传入一个代码块:

 capjobs = CapJobs.new
 capjobs.execute(parameters, @site.id) do |id|
   asite = Site.find(id)
   asite.records.create!(:date => DateTime.now, :action => "Created", :type => :init)
   asite.status = "On Demo"
   asite.dev = true
   asite.save
 end

在没有使用 delayed_job 运行时,这个代码能正常工作,但当使用它时,我会得到以下错误

2012-08-13T09:24:36-0300: [Worker(delayed_job host:eagle pid:12089)] SitesHelper::CapJobs#execute_without_delay failed with LocalJumpError: no block given (yield) - 0 failed attempts
2012-08-13T09:24:36-0300: [Worker(delayed_job host:eagle pid:12089)] PERMANENTLY removing SitesHelper::CapJobs#execute_without_delay because of 1 consecutive failures.
2012-08-13T09:24:36-0300: [Worker(delayed_job host:eagle pid:12089)] 1 jobs processed at 0.0572 j/s, 1 failed ...

看起来没有获取到传入的代码块。这样做不正确吗?还是我应该寻找其他方法?

3个回答

11

delayed_job通过将作业保存到数据存储区(通常是主数据库),然后在后台进程中从该数据存储区加载作业并进行处理/执行。

为了将作业保存到数据库中,delayed_job需要以某种方式保存要调用哪个对象上的哪个方法以及使用哪些参数。这是通过将所有内容序列化为字符串来完成的(delayed_job使用yaml)。不幸的是,块无法被序列化。因此,后台工作程序不知道块参数,并在没有它的情况下调用该方法。当方法尝试传递给块时,这会导致LocalJumpError出现。


2
我找到了一种方法来实现这个。虽然有点hacky,但效果很好。我找到了这篇文章,讲述了创建SerializableProc类的方法。如果我将其传递给函数,则一切都很顺利。

0

大多数人会将这视为一个抽象问题。

proc代码可能不会在运行时更改(除了变量),因此您应该将块代码转换为类或实例方法。传递该方法的名称,然后在execute方法中调用它,例如

@some_data = CapJobs.send( target_method )

或者更好的是

@some_data = DomainSpecificModel.send( target_method )


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