开发者

How to update partial after completing job

This is my first post here but I have gotten some great info from this site already. So I thought someone may be able to help.

In my view I have a form that once submitted, the controller passes the job off to navvy and it really works well. The problem is I would like to have another partial on the same page as the form update with the new info once navvy is done working. So in my controller I have:

Navvy::Job.enqueue( GetZip, :get_zip,  @series, :job_options => {:priority => 8})

And then in my navvy block which is located in config/initializers/navvy.rb I have:

class GetZip
def self.get_zip(params)
  fetch = Fetch.new
  fetch.get_zip(params)
# What to put here to update partial #
end
end

Which works as expected. I am just not sure how I can have the partial开发者_StackOverflow中文版 in my view updated once the navvy job is completed. Any suggestions would be greatly appreciated.


The problem here is that once you've fired up a background process you're no longer tied into that user's request (which is obviously the point of the background process).

So your background job is not aware of what the user is doing in the meantime. For example they could navigate to another page, or even leave your website.

You could get your background job to create a record in a database that indicates it has started processing and update this status when it has finished processing. That way when the user next refreshes the page you can check the status of that record and the partial can be updated accordingly.

If you want the page to auto-update you could keep polling the status of that record with ajax requests. On the initial submission of the form you could start the polling rather than have it running all the time.


Here's what I'm using. This is where the Job is called:

Setting::progress = "Starting..."
Navvy::Job.enqueue(EmailWorker, :async_email, stuff)

Settings is super simple:

class Setting < ActiveRecord::Base
  def Setting::progress=(value)
    setn = Setting.find_or_initialize_by_name("email_status")
    setn.value = value
    setn.save
  end
end

and the navvy job EmailWorker is:

class EmailWorker
  def self.async_email(options)
    # send one at a time
    total = options[:list].length
    errors = []
    options[:list].each_with_index do |email_addr, n|
      begin
        Setting::progress = "#{n+1}/#{total}: #{email_addr}"
        Postoffice.one_notice(email_addr, options).deliver
      rescue Exception => e
        Setting::progress = "#{email_addr} #{e.message}"
        errors << "<span class='red'>#{email_addr}</span> #{e.message}"
      end     
      # get stack level too deep errors at random when this is removed. I don't get it.
      sleep 0.05 
    end
    Setting::progress = "DONE sending #{total} with #{errors.length} errors<br/>#{errors.join("<br/>")}"
    "Done"  # just for display in Navvy console output
  end
end

Then the triggering page has this:

<%- 
# had to add this back as rails 3 took it away
  def periodically_call_remote(options = {})
    frequency = options[:frequency] || 10 # every ten seconds by default
    code = "new PeriodicalExecuter(function() {#{remote_function(options)}}, #{frequency})"
    javascript_tag(code)
  end
-%>
<script type="text/javascript">
//<![CDATA[
  check_var = true;
//]]>
</script>
<%= periodically_call_remote(
      :condition => "check_var == true",
      :url => { :controller => "application", 
      :action => "update" }, 
      :frequency => '3') -%>
<div id="progress">
  <p>Monitoring progress of emails</p>
</div>

And heres the method that's called repeatedly:

def update
  raise "not for direct" if (!request.xhr?)
  @progress = Setting::progress
  @again = !(/^DONE/ =~ @progress)
  render :action => "update"
end

Which trigers an in-place update via update.rjs

page.assign('check_var', @again)
page.replace_html "progress", :partial => "info", :locals => { :info => @progress } 
page.visual_effect :highlight, 'progress', :startcolor => "#3333ff",  :restorecolor => '#ffffff', :duration => 0.5

One word of warning about Navvy - since it runs as a background task until killed, it will stay executing your old app when you cap deploy. You must kill navvy in old "current" and move to new "current".

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜