简体   繁体   English

将块传递给delayed_job

[英]Passing a Block to a delayed_job

I have a function that is marked to be handled asynchronously by delayed_job: 我有一个标记为由delayed_job异步处理的函数:

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 

When I run this function I pass in a block: 当我运行这个函数时,我传入一个块:

 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

This works fine when run without delayed_job but when run with it I get the following error 这在没有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 ...

It seems not to pick up the block that was passed in. Is this not the correct way of doing this or should I find a different method? 它似乎没有拿起传入的块。这不是正确的方法,或者我应该找到一个不同的方法?

delayed_job works by saving your jobs into a data store (most often your primary database) and then loading the jobs out of this data store in a background process, where it is handled/executed. delayed_job的工作原理是将作业保存到数据存储(通常是主数据库)中,然后在后台进程中将作业加载到此数据存储中,并在其中处理/执行。

To save a job into the database, delayed_job needs to somehow save what method to call on which object with what arguments. 要将作业保存到数据库中,delayed_job需要以某种方式保存使用什么参数调用哪个对象的方法。 This is done by serializing everything into a string (delayed_job uses yaml for that). 这是通过将所有内容序列化为字符串来完成的(delayed_job使用yaml )。 Unfortunately, blocks cannot be serialized. 不幸的是,块无法序列化。 So the background worker does not know about the block argument and calls the method without it. 所以后台工作者不知道块参数,并在没有它的情况下调用该方法。 This results in the LocalJumpError when the method is trying to yield to the block. 当方法试图屈服于块时,这会导致LocalJumpError

I found a method of doing this. 我找到了一种方法。 It is kind of hacky but works well. 它有点hacky但效果很好。 I found this article that talks about creating a SerializableProc class. 我发现这篇文章讨论了如何创建SerializableProc类。 If I pass this to the function then everything works great. 如果我把它传递给函数,那么一切都很好。

Most people would treat this as an abstraction problem. 大多数人会将此视为抽象问题。

The proc code is probably not changing from run-to-run (except vars) and so you should make the block code into a class or instance method. proc代码可能不会从run-to-run(vars除外)改变,所以你应该将块代码变成类或实例方法。 Pass the name of that method, and then call it in your execute method, like 传递该方法的名称,然后在execute方法中调用它,如

@some_data = CapJobs.send( target_method )

or perhaps-better-even 或许甚至更好

@some_data = DomainSpecificModel.send( target_method )

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM