Handling Rails Background and Batch Jobs with BackgrounDRb

Posted by Daniel Butler Tue, 23 May 2006 11:20:00 GMT

Ezra Zygmuntowicz has announced the alpha release of a framework to help you manage long running background tasks in Ruby on Rails applications. Ezra describes it as follows:

BackgrounDRb is a small framework for divorcing long running tasks from Rails request/response cycle. With HTTP it is usually not a very good idea to keep a request waiting for a response for long running actions. BackgrounDRb also allows for status updates that in combination with ajax can render live progress bars in the browser while the background worker task gets completed. The MiddleMan can also be used as a cache. You can store rendered templates or compute intensive results in the MiddleMan for use later.

DRb Progress Bar Movie
DRb Ajax Tail Demonstration Movie
Ezra’s BackgroundDRb Article at brainspl.at

Read more for example code.

Example Worker class code:

class FooWorker
  include DRbUndumped

  def initialize(options={})
    @progress = 0
    @results = []
    @options = options
    start_working
  end

  def start_working
    # Work loop goes inside a new thread so it doesn't block
    # rails while it works. A neat way to do progress bars in
    # the browser is to have a @progress instance var that is
    # initialized to 0 and then gets bumped up by your long 
    # running task. This way you can poll for the progress
    # of your job via ajax and update a client side progress bar.
    Thread.new do
      # main work loop goes here. do work and update the
      # progress bar instance var.
      while something
        @results << foo(@options)
        @progress += 1
        break if @progress > 99
      end
    end  
  end

  def results
    @results
  end

  def progress
    puts "Rails is fetching progress: #{@progress}" 
    @progress
  end      
end

Example controller code:

# start new worker and put the job_key into the session so you can 
# get the status of your job later.
def background_task
  session[:job_key] = MiddleMan.new_worker(:class => :foo_worker,
    :args => {:baz => 'hello!', :qux => 'another arg!})
end

def task_progress
  if request.xhr?
    progress = MiddleMan.get_worker(session[:job_key]).progress
    render :update do |page|
      page.replace_html(
        'progress', 
        "<h3>#{progress}% done</h3>" +
        "<img src='/images/progress.gif' " +
        "width='#{progress * 2}' height='15' />")
      if progress == 100
         page.redirect_to :action => 'results'
      end   
    end 
  else
    redirect_to :action => 'index'   
  end
end

def results
  @results = MiddleMan.get_worker(session[:job_key]).results
  MiddleMan.delete_worker(session[:job_key])
end

BackgrounDRb installs as a plugin, and all code resides within your Rails application. Because it can communicate to remote servers via DRb, you can launch your long-running tasks on other machines if necessary. It looks like it’ll soon become a very useful framework for building Rails front-ends to existing applications, and for handling user interaction with batch processes.

Enjoy.

Posted in  | 2 comments

Sponsored Links

Sponsored Links

Comments

  1. Avatar Daniel said 4 days later:

    Ezra has just posted a new release which implements BackgrounDRb as a full-fledged plugin, “complete with rake tasks for installing the start stop scripts, a generator for creating new worker classes, and rake tasks to start and stop the server.”

  2. Avatar Brent said 198 days later:

    Any idea when Windows support will be returned?

(leave url/email »)

   Comment Markup Help Preview comment